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


91

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();
}

3
たぶん、あなたは、拡張メソッドでそれを行うことができます。stackoverflow.com/questions/1243921/...
HCB

回答:


47

C#のインターフェイスで静的メンバーを定義することはできません。インターフェイスはインスタンスのコントラクトです

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

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


64
-1と言うとAn interface is a contract, not an implementation.-それは本当ですが、静的メソッドは実装自体の一部ではないため、ここでは完全に無関係です(非sequitur)-実装は、定義上、データに基づいており、静的メンバーはアクセスできません。-メンバーは通常、ユーティリティメソッドであることに注意してくださいAn interface type definition can define and implement static methods (see §8.4.3) since static methods are associated with the interface type itself rather than with any value of the type.static

2
私はあなたの発言を理解し、同意します。あなたのコメントも重要な文脈であると感じています。しかし。インターフェイスを設計するときは、それをコントラクトと見なす必要があります。これは、静的メソッドが適用されないことを意味します。一部の人々がインターフェースの目的を理解するのを助けるために、そこに残しておくべきだと思いました。コミュニティはそれを削除すべきだと感じていますか?
davisoa 2016

1
An interface is a contract, not an implementationはそれが役に立たないことに部分的に同意します、時には少し文脈化が本当に役立つことがあります。私は完全に同意するとstatic method is not a part of implementation itself 、静的メソッドを持つ実装を、彼らは別のメソッドの実装に実装として使用した場合にのみ、実装の一部になります。しかし、私の辞書は学んだことに基づいています。私の知る限り、用語はプログラミング言語によっても実際には異なります。とにかく実装は1つしかないため、静的メソッドをインターフェースにすることはできません。
CoffeDeveloper 2016

個人の出身国名を指定するIPerson契約があるとしGetCountryます...FrenchPersonエンティティはすべて「フランス」と表示GermanPersonされ、すべて「ドイツ」と表示されます。これは、MSのように異なるタイプのエンティティが同じ(データ)テーブルを共有する場合にも役立ちます。 Azureの一つは、言うConnectionPostCommentに格納されているUsers木のエンティティが共有情報を持っているので、AzureTableIUsers持つことができるGetTableName静的メソッドを...
セルジュ

@ vaxquis-私見、「その契約」は、文が言い換えられた場合に関連します:「インターフェースはインスタンスの契約です。静的メンバーはタイプの一部です。この言い換えられた文は、インスタンスコントラクトでは意味がないことを(正しく)述べています。したがって、問題は単に不正確な表現であり、前後関係ではないと思います。
toolmakerSteve 2018

112

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

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

public interface IMyInterface
{
    void MyMethod();
}

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

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

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


18
なぜ誰もがこれをやりたいのか疑問に思っている人にとっては、静的メソッドを実装するレガシーコードのユニット/統合テストを書くときに特に役立ちます。
デザモンド2017年

この手法は、データを永続化する必要があるがデータベースを使用できない迅速なRESTfulAPIを実装するのに非常にうまく機能しました。実装はインメモリC#オブジェクトでのみ機能していたため、データを格納する場所はありませんでしたが、静的プロパティを使用すると、EFCoreまたはSQLiteを使用したインメモリデータベースの必要性が軽減されました。
gware

19

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

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

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

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

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

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


10
参考までCLS Rule 19: CLS-compliant interfaces shall not define static methods, nor shall they define fields.に、CLS準拠のコンシューマーがこれらの種類のインターフェースを拒否しても問題はないと述べています。1年ほど前に、インターフェイスで静的メソッドを呼び出そうとしましたが、C#コンパイラはそれをコンパイルしませんでした。
クリストファーカレンズ2013年

@ChristopherCurrensのCLSに関する注記に加えて:Common Language Specification (CLS) is a set of basic language features that .Net Languages needed.... When there is a situation to communicate Objects written in different .Net Complaint languages , those objects must expose the features that are common to all the languages. CLSが異なる.NET言語間の相互運用性に関するものであり、C#がインターフェイス上の静的メンバーを許可しない場合、CLSはそれらも禁止し、他の.NET言語はC#から呼び出すことができます。
Simon Tewsi 2017年

17

静的メソッドはC#8で定義できますが、デフォルトの本体を宣言する必要があります。

    public interface IMyInterface
    {
          static string GetHello() =>  "Default Hello from interface" ;
          static void WriteWorld() => Console.WriteLine("Writing World from interface");
    }

または、デフォルトの本文を使用したくない場合は、単に例外をスローします。

    public interface IMyInterface
    {
          static string GetHello() =>  throw new NotImplementedException() ;
          static void WriteWorld() => throw new NotImplementedException();
    }

インターフェイスインスタンスからアクセスできないため、インターフェイスの静的メンバーはかなり役に立たないようです。C#8の少なくとも
パベルSapehin

3
インターフェイス実装の観点として、あなたの権利。それは役に立たない。ただし、この方法では、少なくとも、このインターフェイスを使用しているすべてのクラスにメソッドが実装されているはずです。(これはインターフェイスのオプションの実装の一種です)
AliReza

5

リフレクションを使用して呼び出すことができます。

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

5
また、MyInterfaceのインスタンスがない場合は、「myInterface.GetType()」の代わりに「typeOf(MyInterface)」を使用できます。
RenniePet 2016

当時は良い考えのようで、リフレクションを介してそれを続けるかもしれませんが、1つの小さな警告:メソッドStaticMethodの名前が変更されるようにプログラムが難読化されると、さらに問題が発生します。
RenniePet 2016年

1
@RenniePet:代わりにnameof(StaticMethod)を使用して、StaticMethodの名前変更を部分的に処理できます。名前の変更方法によっては、難読化ツールに役立つ場合があります。この方法で行うと、少なくともコンパイル時エラーが発生します。
ブレントリッテンハウス2017

この場合、反射は極端すぎます
StepanIvanenko19年

3

C# "Ten"は、ロールとともに、インターフェイス上の静的メンバーを許可します。これは大きな前進であり、リフレクションを使用せずにジェネリック演算子のオーバーロードも可能になります。これは、古典的なモノイドの例を使用した、それがどのように機能するかのスニペットの例です。これは、「追加できるもの」という専門用語です。Mads Torgersenから直接取得:C#to the Future

interface IMonoid<T>
{
    static T Zero { get; }
    static T operator +(T t1, T t2);
}

public static T AddAll<T>(T[] ts) where T : IMonoid<T>
{
    T result = T.Zero;
    foreach (T t in ts) { result += t; }
    return result;
}

role IntAddMonoid extends int : IMonoid<int>
{
    public static int Zero => 0;
}

IntAddMonoid[] values = new int[] {1, 2, 4, 8, 16, 32};
int sixtyThree = AddAll<IntAddMonoid>(values); // == 63

追加リソース:

Jeremy Bytes:C#8インターフェイス静的メンバー

編集

この投稿では、当初、インターフェイスの静的メンバーがC#8.0で追加されると述べていましたが、これは正しくありません。ビデオ内のMadsTorgersenの言葉を誤解しました。公式のC#8.0ガイドでは、静的インターフェイスメンバーについてはまだ説明していませんが、かなり長い間取り組んできたことは明らかです。


1

インターフェイスに静的メソッドを設定できない理由については、次のとおりです。 C#で静的メソッドにインターフェイスの実装を許可しないのはなぜですか?

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

すなわち

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

public interface IStaticWrapper
{
    void MyMethod();
}

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

インターフェイスのみを使用するよりも静的クラスでインターフェイスを使用する利点は何ですか?
セレン

1

C#8はインターフェイスで静的メンバーを許可します

C#8.0以降、インターフェイスはメンバーのデフォルトの実装を定義する場合があります。また、共通機能の単一の実装を提供するために、静的メンバーを定義する場合もあります。

インターフェイス(C#リファレンス)

例えば

public interface IGetSomething
{
    public static string Something = "something";
}

var something = IGetSomething.Something;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.