web-dev-qa-db-ja.com

インターフェイスに静的メソッドを実装するにはどうすればよいですか?

C#から呼び出すサードパーティのC++ DLLがあります。

メソッドは静的です。

私はそれを抽象化していくつかのユニットテストを行いたいので、静的メソッドを含むインターフェースを作成しましたが、今ではプログラムエラーが発生します:

修飾子 'static'はこのアイテムには無効です

MyMethod cannot be accessed with an instance reference; qualify it with a type name instead

この抽象化をどのように達成できますか?

私のコードはこんな感じ

private IInterfaceWithStaticMethods MyInterface;

public MyClass(IInterfaceWithStaticMethods myInterface)
{
  this.MyInterface = myInterface;
}

public void MyMethod()
{
  MyInterface.StaticMethod();
}
72
Jon

C#のインターフェイスで静的メンバーを定義することはできません。インターフェースは契約ですインスタンスの場合

現在のようにインターフェースを作成することをお勧めしますが、staticキーワードは使用しません。次に、インターフェイスを実装し、静的C++メソッドを呼び出すクラスStaticIInterfaceを作成します。単体テストを行うには、別のクラスFakeIInterfaceを作成します。このクラスもインターフェイスを実装しますが、単体テストを処理するために必要なことは行います。

これらの2つのクラスを定義したら、環境に必要なクラスを作成し、MyClassのコンストラクターに渡すことができます。

38
davisoa

インターフェイスに静的メンバーを含めることはできず、静的メソッドをインターフェイスメソッドの実装として使用することはできません。

できることは、明示的なインターフェイス実装を使用することです。

public interface IMyInterface
{
    void MyMethod();
}

public class MyClass : IMyInterface
{
    static void MyMethod()
    {
    }

    void IMyInterface.MyMethod()
    {
        MyClass.MyMethod();
    }
}

または、インスタンス固有のメンバーにアクセスしない場合でも、単純に非静的メソッドを使用できます。

83
Danny Varod

静的メンバーは、C#ではなくCLRで完全に合法です。

ILに接着剤を実装して、実装の詳細をリンクできます。

しかし、C#コンパイラがそれらの呼び出しを許可するかどうかはわかりませんか?

8.9.4インターフェイスタイプ定義ECMA-335を参照してください。

インターフェイスタイプの値の表現については何も言わないため、インターフェイスタイプは必ずしも不完全です。このため、インターフェイスタイプの定義では、インターフェイスタイプの値のフィールド定義(インスタンスフィールドなど)を提供しませんが、静的フィールドを宣言できます(§8.4.3を参照)。

同様に、インターフェイスタイプ定義は、そのタイプの値に対するメソッドの実装を提供しません。ただし、インターフェイスタイプ定義は、サポートするタイプによって実装されるメソッドコントラクト(メソッド名とメソッドシグネチャ)を定義できます(通常は定義します)。静的メソッドは型の値ではなくインターフェース型自体に関連付けられているため、インターフェース型定義は静的メソッドを定義および実装できます(§8.4.3を参照)。

16
leppie

リフレクションで呼び出すことができます:

MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);
5
John Koerner

インターフェイスで静的メソッドを使用できない理由については、次のとおりです。 C#が静的メソッドによるインターフェイスの実装を許可しない理由

ただし、インスタンスメソッドを優先して静的メソッドを削除することをお勧めします。それが不可能な場合は、静的メソッド呼び出しをインスタンスメソッド内にラップし、そのインターフェイスを作成して、そこからユニットテストを実行できます。

すなわち

public static class MyStaticClass
{
    public static void MyStaticMethod()
    {...}
}

public interface IStaticWrapper
{
    void MyMethod();
}

public class MyClass : IStaticWrapper
{
    public void MyMethod()
    {
        MyStaticClass.MyStaticMethod();
    }
}
0
Justin Pihony