10

codeplexでASP.NET MVC ソース コードを参照しているときに、インターフェイスを明示的に実装するクラスが一般的であることがわかりました。明示的に実装されたメソッド/プロパティは、同じ名前の別の「保護された仮想」メソッド/プロパティを呼び出します。

例えば、

public class MvcHandler : IHttpHandler, IRequiresSessionState 
{
    protected virtual bool IsReusable 
    {
        get 
        {
           return false;
        }
    }

    bool IHttpHandler.IsReusable 
    {
        get 
        {
           return IsReusable;
        }
    }
}

私は今、この種のプログラミングの利点が何であるかを確信しています。私にとっては、インターフェイス IHttpHandler を暗黙的に実装することを好みます。

作成者は、 MvcHandlerにパブリック プロパティIsResuableを持たせたくないだけだと思います。プロパティIsReusableは、 MvcHandlerのインスタンスがIHttpHandlerとして扱われる場合にのみ使用できます。それでも、なぜ作者がこのようにしたのかはわかりません。

このスタイルのインターフェイス実装の利点を知っている人はいますか?

4

3 に答える 3

14

MVC に固有のものではありませんが、このアプローチにより、コアの公開 API をクリーンに保つことができます。これは、異なるインターフェースなどで同じ名前と署名を持つが意味が異なるというリスクがある場合にも役立ちます。実際には、これはまれです。

また、サブクラスで戻り値の型を変更する実装を提供することもできます。

ICloneable簡単にするために選択しました-定義が不十分なインターフェースであるという事実にこだわらないでください...より良い例はDbCommand、これを行うetcのようなものです-しかし、短い例で示すのは難しいです)

class Foo : ICloneable
{
    public Foo Clone() { return CloneCore(); }
    object ICloneable.Clone() { return CloneCore(); }
    protected virtual Foo CloneCore() { ... }
}

class Bar : Foo
{
    protected override Foo CloneCore() { ... }
    public new Bar Clone() { return (Bar)CloneCore(); }
}

パブリック仮想メソッドを使用した場合、両方を行うことは許可されていないため、それを基本クラスで使用するoverrideことはできません。new

class A
{
    public virtual A SomeMethod() { ... }
}
class B : A
{
    public override A SomeMethod() { ... }
    //Error 1   Type 'B' already defines a member called 'SomeMethod' with the same parameter types
    public new B SomeMethod() { ... }
}

保護された仮想アプローチを使用すると、あらゆる用途:

  • Foo.Clone()
  • Bar.Clone()
  • ICloneable.Clone()

CloneCore()すべてが具象型の正しい実装を使用します。

于 2008-11-11T10:17:41.177 に答える
2

IFoo.Barクラスが明示的に実装し、派生クラスがIFoo.Bar別のことを行う必要がある場合、派生クラスがそのメソッドの基本クラスの実装を呼び出す方法はありません。再実装しない派生クラスは、IFoo.Barを介して基本クラスの実装を呼び出すことができますが、派生クラスが (動作を変更するために((IFoo)this).Bar()再実装する必要があるため) 再実装する場合、前述の呼び出しは派生クラス re に移動します。 IFoo.Bar- 実装ではなく、基本クラスの実装。インターフェイス型への参照をキャストすると、キャストされた (インスタンス インスタンスの型で((IFoo)(BaseType)this).barはなく) 参照の型に関する情報が破棄されるため、役に立ちません。

明示的なインターフェイス実装で保護されたメソッドを呼び出すだけで、この問題を回避できます。これは、派生クラスが仮想メソッドをオーバーライドすることでインターフェイス メソッドの動作を変更できる一方で、必要に応じて基本実装を呼び出す機能を保持できるためです。私見ですが、C# には CLS 準拠の名前を持つ仮想メソッドを生成する明示的なインターフェイス実装が必要でしIFoo.Barた。派生クラスは を再実装でき、再実装しない派生クラスはそれ自体を呼び出すことができるため、明示的な実装を封印することに有用な目的があるとは思えません。override void IFoo.BarOverrides Sub Explicit_IFoo_Bar()IFoo.BarIFoo.Bar

ちなみに、vb.net では、通常のパターンは単に でProtected Overridable Sub IFoo_Bar() Implements IFoo.Barあり、別の仮想メソッドは必要ありません。

于 2013-01-06T18:55:22.880 に答える
1
  1. メンバーが明示的に実装されている場合、クラス インスタンスを介してアクセスすることはできず、インターフェイスのインスタンスを介してのみアクセスできます。参考:Explicit Interfaceの実装チュートリアル
  2. 私の経験では、インターフェイスの実装者がインターフェイスを明示的に実装すると、インターフェイスからメソッドを削除した後、コンパイラ エラーが発生しますが、暗黙的に実装し、メソッドがコードに残るかどうかは通知されません。

理由 1 のサンプル:

public interface IFoo
{
    void method1();
    void method2();
}

public class Foo : IFoo
{
    // you can't declare explicit implemented method as public
    void IFoo.method1() 
    {
    }

    public void method2()
    {
    }

    private void test()
    {
        var foo = new Foo();
        foo.method1(); //ERROR: not accessible because foo is object instance
        method1(); //ERROR: not accessible because foo is object instance
        foo.method2(); //OK
        method2(); //OK

        IFoo ifoo = new Foo();
        ifoo.method1(); //OK, because ifoo declared as interface
        ifoo.method2(); //OK
    }
}
于 2012-08-23T16:40:20.393 に答える