0

インターフェイスを実装するだけでなく継承も行う 2 つのクラスがある場合、関数を仮想化する必要がありますか? 例:

interface IDoSomething
{
    void DoSomething();
}

class A : IDoSomething
{
    public void DoSomething()
    {
        //do A
    }
}

class B : A
{
    public new void DoSomething()
    {
        //do B
    }
}

次のコードは A または B を実行しますか?

IDoSomething doer = new B();
doer.DoSomething(); //do A or do B?

すべてのインターフェイス呼び出しが事実上仮想的であるという印象を受けているため、混乱していますが、明らかに new 演算子を使用して基本定義を非表示にしています。

4

4 に答える 4

4

これが説明です。stackoverflow フォーラムで既に利用可能です。

ここでCSharp 3rd Editionを介してCLRからJeffrey Ritcherを引用

CLR では、インターフェイス メソッドを仮想としてマークする必要があります。ソース コードでメソッドを仮想として明示的にマークしない場合、コンパイラはメソッドを仮想およびシールとしてマークします。これにより、派生クラスがインターフェイス メソッドをオーバーライドできなくなります。メソッドを仮想として明示的にマークすると、コンパイラはメソッドを仮想としてマークします (そして封印されないままにします)。これにより、派生クラスがインターフェイス メソッドをオーバーライドできます。インターフェイス メソッドがシールされている場合、派生クラスはメソッドをオーバーライドできません。ただし、派生クラスは同じインターフェイスを再継承し、インターフェイスのメソッドに独自の実装を提供できます。

于 2012-06-12T11:29:41.987 に答える
2
class A : IDoSomething
{
    public virtual void DoSomething()
    {
        //do A
    }
}

class B : A
{
    public override void DoSomething()
    {
        //do B
    }
}
于 2012-06-12T11:28:54.713 に答える
0

C#と.netでは、派生クラスでインターフェイスメソッドを再実装できますが、派生クラスが可能性のある状況では、基本クラスで仮想メソッドを使用してインターフェイスを実装し、派生クラスでそのメソッドをオーバーライドする方がよい場合がよくあります。基本クラスの実装を完全に置き換えるのではなく、拡張したい。vb.netなどの一部の言語では、クラスが実装されているインターフェイスメンバーと同じ名前と署名を持つパブリックメンバーを公開しているかどうかに関係なく、これを直接実行できます。C#のような他の言語では、インターフェイスを実装するパブリックメソッドを非封印および仮想としてマークできます(派生クラスがそれをオーバーライドし、そのオーバーライド呼び出しをbase.Member(params)行うことができますが、明示的なインターフェイス実装はできません。そのような言語では、できる最善の方法は何かです。お気に入り:

クラスMyClass:MyInterface
{{
  void MyInterface.DoSomething(int param)
  {{
    doSomething(param);
  }
  保護された仮想voiddoSomething(int param)
  {{
    ..。
  }
}
クラスMyClass2:MyClass
{{
  保護されたオーバーライドvoiddoSomething(int param)
  {{
    ..。
    base.doSomething(param);
    ..。
  }
}

場合によっては、インターフェイス実装に仮想呼び出しをラップさせると、基本クラスがオーバーライドされた関数の前または後に特定のことが確実に発生するようになるため、有利な場合があります。たとえば、Disposeの非仮想インターフェイス実装は、仮想Disposeメソッドをラップできます。

  int DisposedFlag; //System.BooleanはInterlocked.Exchangeでは機能しません
  void IDisposable.Dispose()
  {{
    if(Threading.Interlocked.CompareExchange(DisposedFlag、1、0)== 0)
    {{
      Dispose(true);
      DisposedFlag = 2;
      Threading.Thread.MemoryBarrier();
      GC.SuppressFinalize(this);
    }
  }
  public bool Disposed {get {return(DisposedFlag!= 0);}}
  public bool FullyDisposed {get {return(DisposedFlag> 1);}}

これにより、(Microsoftのデフォルトのラッパーとは異なり)Dispose複数のスレッドが同時に呼び出そうとしても、一度だけ呼び出されるようになります。さらに、それはDisposedプロパティを利用可能にします。Microsoftのラッパーを使用すると、フラグが必要なすべての派生クラスはDisposed、独自のラッパーを定義する必要があります。基本クラスのDisposedフラグが保護または公開されている場合でも、派生クラスが既にクリーンアップを開始するまで設定されないため、安全に使用することはできません。ラッパー内に設定DisposingFlagすると、その問題を回避できます。

于 2012-06-12T15:12:33.343 に答える
0

leppie私はのソリューションを好みます。それができない場合:

class A : IDoSomething
{
    void IDoSomething.DoSomething()
    {
        //do A
    }
}

class B : A
{
    void IDoSomething.DoSomething()
    {
        //do B
    }
}

ただし、これは実装を非表示にするため、実行できないことに注意してください((A)doer).DoSomething()

クラス A をこれらのソリューションのいずれかに変更できない場合、すべての場合にそれをオーバーライドする確実な方法はないと思います。インターフェイスを明示的に実装し、public newB でメソッドを作成することもできます。そうすれば、静的に anIDoSomethingまたは a として知られているB場合は B の実装を使用しますが、 an として知られている場合AでもAの実装を使用します。

于 2012-06-12T11:32:53.470 に答える