web-dev-qa-db-ja.com

C#で静的メソッドをオーバーライドできますか?

staticメソッドは暗黙的にfinalであるため、オーバーライドできないと言われました。本当?

  1. 誰かが静的メソッドをオーバーライドするより良い例を与えることができますか?

  2. 静的メソッドが単なるクラスメソッドである場合、それらを実際に使用する方法は何ですか?

34
aspiring

(1)静的メソッドはオーバーライドできませんが、「new」キーワードを使用して非表示にすることができます。ほとんどのメソッドのオーバーライドは、ベース型を参照し、派生メソッドを呼び出すことを意味します。静的は型の一部であり、意味のないvtableルックアップの対象ではないためです。

例えば。スタティックはできません:

public class Foo { 
    public virtual void Bar() { ... }
}
public class Bar : Foo {
    public override void Bar() { ... }
}

// use:
Foo foo = new Bar(); // make an instance
foo.Bar(); // calls Bar::Bar

インスタンスでは静的変数が機能しないため、常にFoo.BarまたはBar.Barを明示的に指定します。したがって、ここでオーバーライドすることは意味がありません(コードで表現してみてください...)。

(2)静的メソッドにはさまざまな使用法があります。たとえば、単一の型のインスタンスを取得するためにシングルトンパターンで使用されています。別の例は「static void Main」です。これは、プログラムのメインアクセスポイントです。

基本的には、使用する前にオブジェクトインスタンスを作成したくない、または作成できない場合は常に使用します。たとえば、静的メソッドがオブジェクトを作成するとき。

[更新]

簡単な非表示の例:

public class StaticTest
{
    public static void Foo() { Console.WriteLine("Foo 1"); }
    public static void Bar() { Console.WriteLine("Bar 1"); }
}

public class StaticTest2 : StaticTest
{
    public new static void Foo() { Console.WriteLine("Foo 2"); }
    public static void Some() { Foo(); Bar(); } // Will print Foo 2, Bar 1
}

public class TestStatic
{
    static void Main(string[] args)
    {
        StaticTest2.Foo();
        StaticTest2.Some();
        StaticTest.Foo();
        Console.ReadLine();
    }
}

クラスをstaticにすると、これを実行できないことに注意してください。静的クラスは、objectから派生する必要があります。

これと継承の主な違いは、コンパイラがコンパイル時に静的を使用するときに呼び出すメソッドを決定できることです。オブジェクトのインスタンスがある場合、実行時にこれを行う必要があります(vtableルックアップと呼ばれます)。

32
atlaste

静的メソッドをオーバーライドしません。あなたはそれを隠します。詳細については、 この回答 を参照してください。

静的メソッドを使用するいくつかの理由:

  1. これらは、インスタンスメソッドよりも 少し速い です。これも参照してください msdn article これは、これをバックアップするためのパフォーマンス値を提供します(インライン静的呼び出し平均0.2 ns、静的呼び出し平均6.1ns、インラインインスタンス呼び出し平均1.1 ns、インスタンス呼び出し平均6.8 ns)
  2. 書き出すのが冗長になります-クラスに到達するためにクラスをインスタンス化する必要はありません(そしてインスタンス化もパフォーマンスに影響を与える可能性があります)
5
Yaakov Ellis

静的メソッドをオーバーライドすることはできません。静的メソッドは、クラスのインスタンスに関連していないため、仮想にすることはできません。

派生クラスの「オーバーライドされた」メソッドは、実際には新しいメソッドであり、基本クラスで定義されたメソッドとは無関係です(したがって、新しいキーワードです)。

これは理解する上で重要なことです:型が他の型から継承する場合、それらは共通のコントラクトを満たしますが、静的型はどのコントラクトにもバインドされません(純粋なOOPの観点から)。この言語では、2つの静的型を「継承」コントラクトと結び付ける技術的な方法はありません。2つの異なる場所でLogメソッドを「オーバーライド」する場合。

静的メソッドをオーバーライドすることを考えた場合、実際には意味がありません。仮想ディスパッチを行うには、チェックするオブジェクトの実際のインスタンスが必要です。

静的メソッドはインターフェイスを実装することもできません。このクラスがIRolesServiceインターフェイスを実装している場合、メソッドは静的であってはならないと主張します。インスタンスメソッドを持つ方が良い設計なので、準備ができたらMockRoleServiceを実際のサービスと交換できます

5
Neel