3

C#のインターフェイスメソッドは明示的に実装できるため、インスタンスがインターフェイスタイプに明示的にキャストされると、その実装が呼び出されます。これがクラスの仮想メソッドでもサポートされていないのはなぜですか?

「多重継承」の問題の回避はインターフェースに固有ですが、明示的に実装されたメンバーがインターフェースに役立つ他のすべての理由から、仮想メソッドにも役立つようです。よりクリーンなリターンタイプの共分散モデルが思い浮かびます。

編集:リクエストにより、例:

public class Foo {
    ...
}

public class Bar : Foo {
   ...
}

class Base {
   abstract Foo A ();
}

class Dervied {
  private Bar _b;

  Bar A () {
    return _b;
  }

  Foo Base.A () {
    return _b;
  }
}

私はこれをシミュレートするためにヘルパーメソッドを使用することを知っていますが、正味の効果には、明示的な実装が持つであろう悪い特性のいずれかがあるようですが、より汚いAPIを使用します。私の質問の核心は、戻り型の共分散を行う方法ではなく、インターフェイスの同様のメカニズムが仮想メソッドでサポートされていない理由です。

4

2 に答える 2

5

public virtualそもそもメソッドを持たないことを勧める人もいます。ただし、代わりにpublic、コンシューマー インターフェイスを表す 1 つの非仮想メソッドとprotected virtual、実装者インターフェイスを表す 1 つのメソッドを作成します。

呼び出し側と実装側のコントラクトを分離して「設計を混乱させる」とは言いません。多くの場合、それはよりクリーンな IMO ですが、私は通常、怠け者で実際にそのようにすることはできません。

この設計は、戻り値の型の共分散とメソッドの隠蔽により、はるかにうまく機能します。

これの追加の利点は、publicラッパーが追加のチェック コードを追加でき、呼び出し元と実装者のさまざまなコントラクトをサポートできることです。

戻り値の型の共分散をエミュレートする方法の例:

public class Base
{
    protected virtual Base FooOverride(int i){return new Base();};//FooOverride does not need to duplicate the argument checking

    public Base Foo(int i)
    {
        if(i<0)
          throw new ArgumentException("i<0");
        return FooOverride(i);
    }
}

public class Derived:Base
{
    protected override Base FooOverride(int i){return new Derived();};
    public new Derived Foo(int i)
    {
        return (Derived)base.Foo();
    }
}
于 2011-07-03T16:19:10.250 に答える
3

このようなことを許可する以外に、それにはどのような利点がありますか?

class Base
{
    virtual void M() { }
}

class Derived : Base
{
    override void M() { }

    override void Base.M() { }
}

これにより、 Liskov Substitution Principleの違反がC# 言語に効果的に組み込まれます。Base 型の変数がある場合、それに対して M() を呼び出すと、実行時の型が Base か Derived かによって、まったく異なることができます。

明示的なインターフェイスの実装は異なります。あなたがこれを持っているとしましょう:

interface IFoo
{
    void DoStuff();   
}

interface IBar
{
    void DoStuff();
}

class C : IFoo, IBar
{
    void IFoo.DoStuff() { }

    void IBar.DoStuff() { }
}

これにより、LSP が保持されます。たまたまランタイム タイプ C の IFoo 変数がある場合、それに対して DoStuff() を呼び出すと、その IFoo 実装が取得されます。IBar も同様です。

于 2011-07-03T16:07:41.280 に答える