C#で静的メソッドがインターフェイスを実装できないのはなぜですか?


447

なぜC#はこのように設計されたのですか?

私が理解しているように、インターフェースは動作を説明するだけであり、特定の動作が実装されているインターフェースを実装するクラスの契約上の義務を説明する目的を果たします。

クラスがその振る舞いを共有メソッドに実装したいのであれば、なぜそうすべきではないのでしょうか?

これが私が考えていることの例です:

// These items will be displayed in a list on the screen.
public interface IListItem {
  string ScreenName();
  ...
}

public class Animal: IListItem {
    // All animals will be called "Animal".
    public static string ScreenName() {
        return "Animal";
    }
....
}

public class Person: IListItem {

    private string name;

    // All persons will be called by their individual names.
    public string ScreenName() {
        return name;
    }

    ....

 }

6
まあ、Java 8にはそれがあります(stackoverflow.com/questions/23148471/…)。
リャン2015

1
あなたが相続またはインタフェースの実装で静的な動作を組み合わせることができますどのように参照してください。stackoverflow.com/a/13567309/880990
オリヴィエJacot-Descombes

1
IListItem.ScreenName() => ScreenName()(C#7構文を使用)は、静的メソッドを呼び出すことによって明示的にインターフェイスメソッドを実装します。ただし、継承を追加すると、状況は醜くなります(インターフェースを再実装する必要があります)
Jeroen Mostert

2
待機が終了したことをみんなに知らせるだけです!C#8.0には静的インターフェイスメソッドがあります:dotnetfiddle.net/Lrzy6y(OPが望んでいた方法とは少し異なりますが、実装する必要はありません)
Jamie Twells

回答:


221

あなたがこれを行うことができない理由を尋ねていると仮定すると:

public interface IFoo {
    void Bar();
}

public class Foo: IFoo {
    public static void Bar() {}
}

これは意味的に私には意味がありません。インターフェースで指定されたメソッドは、オブジェクトと対話するための規約を指定するために存在する必要があります。静的メソッドではオブジェクトを操作できません。実装を静的にできる場所にいる場合は、そのメソッドが本当にインターフェースに属しているかどうかを自問する必要があります。


あなたの例を実装するために、Animalにconstプロパティを与え、静的コンテキストからアクセスできるようにし、実装でその値を返します。

public class Animal: IListItem {
    /* Can be tough to come up with a different, yet meaningful name!
     * A different casing convention, like Java has, would help here.
     */
    public const string AnimalScreenName = "Animal";
    public string ScreenName(){ return AnimalScreenName; }
}

さらに複雑な状況では、常に別の静的メソッドを宣言し、それに委任することができます。例を考えてみると、静的コンテキストとインスタンスコンテキストの両方で重要なことを行う理由は考えられなかったので、FooBar blobを省略して、それが可能性があることを示します。良い考えではありません。


6
完璧な例です!しかし、私はあなたの推論を理解しているとは思いません。確かにコンパイラができ、同様statucメンバーで見えるように設計されていますか?インスタンスには、isisメソッドの実装用のアドレスのテーブルがありませんか?静的メソッドをこの表に含めることはできませんか?
Kramii 2008年

12
これが役立つ場合があります。たとえば、すべての実装者がXElement引数を取るGetInstanceメソッドを実装するようにします。私はそれをインターフェースの静的メソッドとして定義することも、インターフェースからコンストラクター署名を要求することもできません。
2011

25
「これは意味がありません」から「バグです。できればいいのですが」まで、多くの人が両側で意見を交わしています。(私はそれについて有効なユースケースがあると思います、それが私がここで終わった方法です。)回避策として、インスタンスメソッドは単に静的メソッドに委任することができます。
harpo

5
public static object MethodName(this IBaseClass base)静的クラス内のように、基本インターフェースに拡張メソッドとしてピースを単純に実装することもできます。ただし、欠点は、インターフェースの継承とは異なり、個々の継承者が方法論をうまくオーバーライドすることを強制/許可しないことです。
Troy Alford、2011年

8
それはジェネリックで非常に理にかなっています。たとえば、void Something <T>()where T:ISomeInterface {new T()。DoSomething1(); T.DoSomething2(); }
フランシスコライアントルマスキーI

173

私の(単純化した)技術的な理由は、静的メソッドがvtableになく、呼び出しサイトがコンパイル時に選択されることです。これは、オーバーライドまたは仮想静的メンバーを持つことができないのと同じ理由です。詳細については、CSのgradまたはコンパイラのwonkが必要です-私はどちらでもありません。

政治的な理由から、私はエリックリッペルト(コンパイラワンクであり、ウォータールー大学で数学、コンピュータサイエンス、および応用数学の学士号を取得しています)を引用します(出典:LinkedIn)。

...静的メソッドの中核となる設計原則、それらに名前を付ける原則... [is] ...コンパイル時に、どのメソッドが呼び出されるかは常に正確に決定できます。つまり、メソッドはコードの静的分析のみで解決できます。

Lippertはいわゆる型メソッドの余地を残していることに注意してください。

つまり、(静的など)型に関連付けられたメソッドは、null不可の「this」引数(インスタンスや仮想とは異なります)を取りませんが、呼び出されたメソッドが構築されたTの型( staticとは異なり、コンパイル時に決定可能でなければなりません)。

しかし、その有用性はまだ確信されていません。


5
すばらしい、これは私が書きたかった答えです-実装の詳細を知りませんでした。
Chris Marasti-Georg、

5
すばらしい答えです。そして、私はこの「タイプメソッド」が欲しいです!非常に多くの場面で役立ちます(型/クラスのメタデータについて考えてください)。
フィリップドーブマイヤー、2012

23
これが正解です。あなたは誰かにインターフェースを渡します、彼らはメソッドを呼び出す方法を知る必要があります。インターフェイスは単なる仮想メソッドテーブルです。静的クラスにはそれがありません。呼び出し元は、メソッドを呼び出す方法を知りません。(私がこの回答を読む前に、C#は単純なことだと思っていました。今で、インターフェイス何であるかによって課される技術的な制限であることを認識しています)。他の人はそれがどのように悪いデザインであるかについてあなたに話します。それは悪い設計ではありません-それは技術的な制限です。
Ian Boyd

2
+1は、質問に実際に回答し、知識や知識を欠いたものではありません。イアン・ボイドが言ったように:「それは悪いデザインではありません-それは技術的な制限です。」
Joshua Pech 2013年

3
関連するvtableを持つ静的クラスのオブジェクトを生成することは完全に可能です。Scalaがをどのように処理objectするか、そしてそれらがどのようにインターフェースの実装を許可されるかを見てください。
セバスチャングラフ、2014年

97

ここでのほとんどの回答は、全体の要点を逃したようです。ポリモーフィズムは、インスタンス間だけでなく、タイプ間でも使用できます。ジェネリックを使用する場合、これが必要になることがよくあります。

ジェネリックメソッドに型パラメーターがあり、それを操作する必要があるとします。コンストラクタを知らないので、インスタンス化したくありません。

例えば:

Repository GetRepository<T>()
{
  //need to call T.IsQueryable, but can't!!!
  //need to call T.RowCount
  //need to call T.DoSomeStaticMath(int param)
}

...
var r = GetRepository<Customer>()

残念ながら、私は「醜い」代替案しか思いつくことができません。

  • 醜いリフレクションを使用して、インターフェイスとポリモーフィズムのアイデアを打ち負かしてください

  • 完全に別のファクトリクラスを作成する

    これにより、コードが非常に複雑になる可能性があります。たとえば、ドメインオブジェクトをモデル化しようとしている場合、各オブジェクトには別のリポジトリクラスが必要になります。

  • インスタンス化してから、目的のインターフェイスメソッドを呼び出します

    ジェネリックパラメーターとして使用されるクラスのソースを制御する場合でも、これを実装するのは難しい場合があります。その理由は、たとえば、インスタンスが既知の「DBに接続された」状態である必要がある場合があるためです。

例:

public class Customer 
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  void SomeOtherMethod() 
  { 
    //do work...
  }
}

静的インターフェイスの問題を解決するためにインスタンス化を使用するには、次のことを行う必要があります。

public class Customer: IDoSomeStaticMath
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  //dummy instance
  public Customer() { IsDummy = true; }

  int DoSomeStaticMath(int a) { }

  void SomeOtherMethod() 
  { 
    if(!IsDummy) 
    {
      //do work...
    }
  }
}

これは明らかに醜く、不必要に他のすべてのメソッドのコードを複雑にします。明らかに、エレガントなソリューションでもありません!


35
+1「ここでのほとんどの回答は全体のポイントを逃しているようです。」; それは...ほとんどすべての答えは、ほとんど役に立たない言い回しを詳細に調べるには、質問のコアをかわすように見えるどのように信じられないほどだ

5
@Chrisここに、私がこの制限に再び当たった具体的な例があります。IResettableインターフェイスをクラスに追加して、サイト管理者がリセットできる静的変数に特定のデータをキャッシュすることを示したい(たとえば、注文カテゴリリスト、VATレートのセット、外部APIから取得したカテゴリのリスト) DBと外部APIのヒットを減らすために、これは明らかに静的メソッドのリセットを使用します。これにより、リセットできるクラスの検出を自動化できます。私はまだこれを行うことができますが、メソッドは強制されず、IDEで自動的に追加されず、希望に依存します。
mattmanser 2012年

6
@Chris同意しない、大過剰。より多くのアーキテクチャが「最良の」ソリューションである場合、それは常に言語の欠陥の兆候です。C#にはジェネリックと無名メソッドが用意されているため、誰も誰も話さないすべてのパターンを覚えていますか?
mattmanser 2012年

3
「T:IQueryable、T:IDoSomeStaticMath」などは使用できませんか?
ロジャーウィルコックス

2
@ ChrisMarasti-Georg:多少汚いが興味深い方法は、この小さな構造ですpublic abstract class DBObject<T> where T : DBObject<T>, new()。次に、すべてのDBクラスをとして継承させDBObject<T>ます。次に、キーによる取得を抽象スーパークラスの戻り型Tの静的関数にして、その関数にTの新しいオブジェクトを作成させ、そのオブジェクトに対して保護されたString GetRetrieveByKeyQuery()(スーパークラスで抽象として定義されている)を呼び出して取得できます。実行する実際のクエリ。これは、トピックオフTAD取得することかもしれないが
Nyerguds

20

私はそれが古い質問であることを知っていますが、それは興味深いです。例は最高ではありません。使用例を示すと、はるかに明確になると思います。

string DoSomething <T>()ここでT:ISomeFunction
{
  if(T.someFunction())
    ...
}

静的メソッドにインターフェースを実装させるだけでは、期待どおりの結果は得られません。必要なのは、インターフェースの一部として静的メンバーを持つことです。私は確かにそのための多くの使用例を想像することができます、特にそれが物を作ることができるということに関しては。役立つかもしれない2つのアプローチを提供できます。

  1. 型パラメーターが上記のDoSomethingに渡す型になる静的なジェネリッククラスを作成します。このクラスの各バリエーションには、そのタイプに関連するものを保持する1つ以上の静的メンバーがあります。この情報は、対象の各クラスに「情報の登録」ルーチンを呼び出させるか、Reflectionを使用してクラスバリエーションの静的コンストラクターの実行時に情報を取得することによって提供できます。後者のアプローチはComparer <T> .Default()などで使用されていると思います。
  2. 対象のクラスTごとに、IGetWhateverClassInfo <T>を実装し、「新しい」制約を満たすクラスまたは構造体を定義します。クラスには実際にはフィールドは含まれませんが、型情報を含む静的フィールドを返す静的プロパティがあります。そのクラスまたは構造体のタイプを問題のジェネリックルーチンに渡します。これにより、インスタンスを作成し、それを使用して他のクラスに関する情報を取得できます。この目的でクラスを使用する場合は、毎回新しい記述子オブジェクトインスタンスを構築する必要がないように、おそらく上記のように静的汎用クラスを定義する必要があります。構造体を使用する場合、インスタンス化のコストはゼロになるはずですが、構造体の種類ごとにDoSomethingルーチンの異なる拡張が必要になります。

これらのアプローチはどれも本当に魅力的ではありません。一方、CLRにこの種の機能を適切に提供するメカニズムが存在する場合、.netはパラメーター化された「新しい」制約を指定できると期待します(クラスに特定のシグネチャを持つコンストラクターがあるかどうかがわかるため)それが特定のシグネチャを持つ静的メソッドを持っているかどうかを知るのと同じくらい困難です


16

近視眼だと思います。

最初に設計されたとき、インターフェースはクラスのインスタンスでのみ使用することを意図していた

IMyInterface val = GetObjectImplementingIMyInterface();
val.SomeThingDefinedinInterface();

ジェネリックスの制約が静的メソッドをインターフェースに追加することは実用的だったので、それはインターフェースの導入によってのみでした。

(コメントへの対応:)今それを変更するには、CLRを変更する必要があり、既存のアセンブリとの非互換性につながると思います。


私が最初に問題に遭遇したのはジェネリックのコンテキストですが、インターフェイスに静的メソッドを含めることが他のコンテキストでも役立つかどうか疑問に思いますか?変更できない理由はありますか?
Kramii 2008年

いくつかのパラメーターを使用してそれ自体を作成するためにパラメーターの型を必要とするジェネリッククラスを実装するときに、私もこれに遭遇します。new()は何も取ることができないので。クラミ、これをどうやってやるのかもうわかったの?
トム

1
@Kramii:静的APIの契約。オブジェクトのインスタンスは必要ありません。特定の署名を保証するだけです。IMatrixMultiplierまたはICustomSerializer。クラスメンバーとしてのFuncs / Actions / Delegatesがトリックを行いますが、IMOはこれはやり過ぎのように思われ、経験の浅いAPIを拡張しようとすると混乱する可能性があります。
David Cuccia

14

インターフェイスはオブジェクトの動作を指定します。

静的メソッドはオブジェクトの動作を指定しませんが、オブジェクトに何らかの影響を与える動作を指定します。


71
すみません。それが正しいとは思いません!インターフェイスは動作を指定しません。インターフェースは、名前付き操作のセットを定義します。2つのクラスは、完全に異なる方法で動作するようにインターフェイスのメソッドを実装できます。したがって、インターフェイスは動作をまったく指定しません。それを実装するクラス。
スコットランガム

1
私がうるさいとは思わないでくださいね。でも、OOを学んでいる人なら理解することが重要だと思います。
スコットランガム、

4
インターフェイスは、動作と表示を含むコントラクトを指定することになっています。そのため、インターフェイスコールの動作を変更することは、両方とも修正されることになっているため、ノーノーです。呼び出しの動作が異なるインターフェイスがある場合(つまり、IList.Addが削除を行った場合)は正しくありません。
ジェフイェーツ

14
ええ、そうです、その名前に反する動作をするメソッドを定義するために頭の中で曲がるでしょう。IAlertService.GetAssistance()があったとしても、その動作としては、ライトを点滅させる、アラームを鳴らす、棒で目を突くなどがあります。
スコットランガム

1
実装は、ログファイルに書き込むこともできます。この動作はインターフェースで指定されていません。しかし、多分あなたは正しいです。「援助を得る」行動は本当に尊重されるべきです。
スコットランガム

14

インターフェースが「契約」を表す限り、静的クラスがインターフェースを実装することは静かに理にかなっています。

上記の議論はすべて、契約についてのこの点を逃しているようです。


2
私はこのシンプルだが効果的な答えに完全に同意します。「静的インターフェース」で興味深いのは、それが契約を表すことです。多分それは「静的インターフェース」と呼ばれるべきではありませんが、私たちはまだ構造を見逃しています。たとえば、ICustomMarshalerインターフェイスに関する.NETの公式ドキュメントを確認してください。「Stringをパラメーターとして受け入れ、戻り値の型がICustomMarshalerであるGetInstanceと呼ばれる静的メソッドを追加する」ことを実装するクラスが必要です。それは真面目に英語で「静的インターフェース」の定義のように真剣に見えますが、C#ではそれを好みます...
Simon Mourier '27 / 10/27

@SimonMourierそのドキュメントはもっと明確に書かれたかもしれませんが、あなたはそれを誤解しています。GetInstance静的メソッドを必要とするのは、ICustomMarshalerインターフェイスではありません。これを必要とするのは[MarshalAs]コード属性です。ファクトリパターンを使用して、属性がアタッチされたマーシャラーのインスタンスを取得できるようにします。残念ながら、MarshalAsドキュメントページにGetInstance要件のドキュメントを含めることを完全に忘れていました(組み込みのマーシャリング実装を使用した例のみを示しています)。
Scott Gartner

@ScottGartner-あなたのポイントを取得しないでください。msdn.microsoft.com/en-us/library/…は、「カスタムマーシャラーインターフェイスの実装に加えて、パラメーターとして文字列を受け取り、戻り値の型がICustomMarshalerであるGetInstanceと呼ばれる静的メソッドを実装する必要があります。静的メソッドは、カスタムマーシャラーのインスタンスをインスタンス化するために、共通言語ランタイムのCOM相互運用層によって呼び出されます。これは明らかに静的な契約定義です。
Simon Mourier 2017年

9

インターフェイスの目的はポリモーフィズムを許可することであり、定義されたインターフェースを実装するためにすべて定義された定義済みクラスの任意の数のインスタンスを渡すことができます...ポリモーフィック呼び出し内でコードが見つけることができることを保証します呼び出すメソッド 静的メソッドがインターフェースを実装できるようにしても意味がありません。

どのように呼びますか?


public interface MyInterface { void MyMethod(); }
public class MyClass: MyInterface
{
    public static void MyMethod() { //Do Something; }
}

 // inside of some other class ...  
 // How would you call the method on the interface ???
    MyClass.MyMethod();  // this calls the method normally 
                         // not through the interface...

    // This next fails you can't cast a classname to a different type... 
    // Only instances can be Cast to a different type...
    MyInterface myItf = MyClass as MyInterface;  

1
他の言語(Javaなど)では、オブジェクトインスタンスから静的メソッドを呼び出すことができますが、静的コンテキストから呼び出す必要があるという警告が表示されます。
Chris Marasti-Georg、

.Netでは、インスタンスから静的メソッドを呼び出すことができます。それは別のことです。静的メソッドがインターフェースを実装している場合、インスタンスなしで呼び出すことができます。それは意味をなさないものです。実装をインターフェースに入れることはできません。それはクラスになければなりません。それで、そのインターフェースを実装するために5つの異なるクラスが定義され、それぞれがこの静的メソッドの異なる実装を持っている場合、コンパイラーはこれを使用しますか?
Charles Bretana、2014

1
ジェネリックの場合、@ CharlesBretanaは、渡されたタイプの1つです。静的メソッドのインターフェースがあると便利です(または、必要に応じて、それらを「静的インターフェース」と呼び、クラスが両方の静的インターフェースを定義できるようにしますおよびインスタンスインターフェース)。私が持っているのであればWhatever<T>() where T:IMyStaticInterface、私は呼び出すことができますWhatever<MyClass>()し、持っているT.MyStaticMethod()内部のWhatever<T>()インスタンスを必要とせずに実装。呼び出すメソッドは実行時に決定されます。これはリフレクションを介して行うことができますが、強制される「契約」はありません。
Jcl

4

非ジェネリックコンテキストで使用される静的メソッドに関しては、インターフェイスへの参照があったとしても呼び出すことができないため、インターフェイスでそれらを許可してもあまり意味がないことに同意します。ただし、多態的なコンテキストではなく、一般的なインターフェイスでインターフェイスを使用して作成された言語設計には、根本的な穴があります。この場合、インターフェースはインターフェースではなく、制約です。C#にはインターフェイスの外側に制約の概念がないため、実質的な機能がありません。適例:

T SumElements<T>(T initVal, T[] values)
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

ここではポリモーフィズムはありません。ジェネリックはオブジェクトの実際のタイプを使用して+ =演算子を呼び出しますが、その演算子が存在することを確実に言えないため、これは失敗します。簡単な解決策は、制約でそれを指定することです。演算子は静的であり、静的メソッドをインターフェイスに含めることはできず(これが問題です)、制約がインターフェイスとして表されるため、単純なソリューションは不可能です。

C#に必要なのは実際の制約タイプです。すべてのインターフェイスも制約になりますが、すべての制約がインターフェイスになるわけではないので、次のようにすることができます。

constraint CHasPlusEquals
{
    static CHasPlusEquals operator + (CHasPlusEquals a, CHasPlusEquals b);
}

T SumElements<T>(T initVal, T[] values) where T : CHasPlusEquals
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

実装するすべての数値型に対してIArithmeticを作成することについてはすでに多くの話がありましたが、制約は多態性コンストラクトではないため、CArithmetic制約を作成するとその問題が解決するため、効率が心配されます。


C#の演算子は静的であるため、これはまだ意味がありません。
John Saunders

つまり、制約はTYPE(インスタンスではない)に+演算子(さらには+ =演算子)があることを確認し、テンプレートを生成できるようにします。実際のテンプレート置換が発生すると、使用されているオブジェクトはその演算子(または他の静的メソッド)を持つ型の場合。次のように言うことができます。SumElements<int>(0、5); これはインスタンス化されます:SumElements(int initVal、int [] values){foreach(var v in values){initVal + = v; もちろん、これは完全に理にかなっています
Jeremy Sorensen 2013

1
テンプレートではないことに注意してください。これはジェネリックであり、C ++テンプレートとは異なります。
John Saunders

@JohnSaunders:ジェネリック医薬品はテンプレートではない、と私は、彼らが合理的に静的にバインドされた事業者で動作するように作ることができる方法を知りませんが、一般的な文脈であることを指定することが有用である可能性があり、多くの例があるT必要があります静的メンバー(Tインスタンスを生成するファクトリなど)。実行時の変更がなくても、言語が構文シュガーなどを効率的かつ相互運用可能な方法で実装できるようにする規則とヘルパーメソッドを定義することは可能だと思います。仮想静的メソッドを使用する各インターフェースにヘルパークラスがある場合...
supercat

1
@JohnSaunders:問題は、メソッドがインターフェイスを実装していることではなく、コンパイラが、選択の基準となるオブジェクトインスタンスがないと呼び出す仮想メソッドを選択できないことです。解決策は、仮想ディスパッチ(機能しない)を使用せずに、代わりに汎用静的クラスの呼び出しを使用して、「静的インターフェース」呼び出しをディスパッチすることです。型ベースの汎用ディスパッチでは、インスタンスを持つ必要はなく、型を持つだけです。
スーパーキャット2013


3

あなたが望むと思われるものは、静的メソッドがTypeまたはそのタイプのインスタンスの両方を介して呼び出されることを可能にします。これは、少なくとも望ましい曖昧さをもたらします。

それが重要であるかどうか、それがベストプラクティスであるかどうか、および何らかの方法でそれを実行しているパフォーマンスの問題があるかどうかについて、無限の議論があります。C#をサポートしないだけで、心配する必要がなくなります。

また、この欲求に準拠したコンパイラーは、インスタンスメソッドと静的メソッドのより厳密な分離を伴う可能性がある最適化を失う可能性があります。


興味深いことに、VB.Netの両方のType ad Instanceで静的メソッドを呼び出すことは可能です(後者の場合、IDEが警告を出す場合でも)。問題ではないようです。あなたは最適化について正しいかもしれません。
Kramii 2008年

3

クラスの静的メソッドと非静的メソッドは、異なるインターフェースであると考えることができます。呼び出されると、静的メソッドはシングルトン静的クラスオブジェクトに解決され、非静的メソッドは処理するクラスのインスタンスに解決されます。したがって、インターフェイスで静的メソッドと非静的メソッドを使用する場合、1つのまとまりのあるものにアクセスするために実際にインターフェイスを使用する必要がある場合、2つのインターフェイスを効果的に宣言することになります。


これは興味深いPOVであり、おそらくC#設計者が考えていたものです。これからは静的メンバーを別の方法で考えます。
Kramii 2008年

3

インターフェイスメソッドの静的実装、またはMark Brackettが「いわゆるタイプメソッド」として導入したもののいずれかが欠けている例を示すには、次のようにします。

データベースストレージから読み取る場合、任意の構造のテーブルからの読み取りを処理する汎用のDataTableクラスがあります。すべてのテーブル固有の情報は、DBからの1行のデータも保持し、IDataRowインターフェイスを実装する必要があるテーブルごとに1つのクラスに入れられます。IDataRowには、データベースから読み取るテーブルの構造の説明が含まれています。DataTableは、DBから読み取る前に、IDataRowからデータ構造を要求する必要があります。現在、これは次のようになります。

interface IDataRow {
  string GetDataSTructre();  // How to read data from the DB
  void Read(IDBDataRow);     // How to populate this datarow from DB data
}

public class DataTable<T> : List<T> where T : IDataRow {

  public string GetDataStructure()
    // Desired: Static or Type method:
    // return (T.GetDataStructure());
    // Required: Instantiate a new class:
    return (new T().GetDataStructure());
  }

}

GetDataStructureは、各テーブルを読み取るために一度だけ必要であり、もう1つのインスタンスをインスタンス化するためのオーバーヘッドは最小限です。しかし、この場合はここでそれはいいでしょう。


1

参考:インターフェースの拡張メソッドを作成することで、希望する動作と同様の動作を得ることができます。拡張メソッドは、共有され、オーバーライドできない静的な動作になります。ただし、残念ながら、この静的メソッドはコントラクトの一部にはなりません。


1

インターフェイスは、定義された利用可能な機能の抽象的なセットです。

そのインターフェースのメソッドが静的として動作するかどうかは、インターフェースの背後に隠されるべき実装の詳細です。ある方法でメソッドを不必要に実装する必要があるため、インターフェイスメソッドを静的として定義するのは誤りです。

メソッドが静的として定義されている場合、インターフェイスを実装するクラスは、カプセル化することができません。カプセル化は、オブジェクト指向の設計で努力することをお勧めします(理由については触れません。http//en.wikipedia.org/wiki/Object-orientedで読むことができます)。このため、静的メソッドはインターフェイスで許可されていません。


1
はい、インターフェース宣言のstaticはばかげています。クラスが特定の方法でインターフェースを実装することを強制されるべきではありません。ただし、C#はクラスを非静的メソッドを使用したインターフェイスの実装に制限していますか?これは理にかなっていますか?どうして?
Kramii 2008年

キーワード「静的」を使用することはできません。ただし、静的に動作するメソッドを作成するためにstaticキーワードを必要としないため、制限はありません。オブジェクトのメンバーにアクセスしないメソッドを記述するだけで、静的メソッドのように動作します。したがって、制限があります。
スコットランガム、

確かにスコットですが、コードの別の部分で、誰かが静的にそのメソッドにアクセスすることはできません。私があなたが望む理由を考えることができるわけではありませんが、それはOPが求めているようです。
Chris Marasti-Georg、

まあ、本当に必要性を感じたなら、コードの別の部分でアクセスするための静的メソッドとして記述し、非静的メソッドを記述して静的メソッドを呼び出すことができます。私は間違っているかもしれませんが、それが質問者の目的ではないかと思います。
スコットランガム

1

静的クラスは、これを一般的に使用できるようにこれを実行できる必要があります。代わりに、望ましい結果を得るにはシングルトンを実装する必要がありました。

「ユーザー」、「チーム」などの各エンティティタイプに対して「作成」、「読み取り」、「更新」、「削除」などのCRUDメソッドを実装した一連の静的ビジネスレイヤークラスがありました。次に、ベースを作成しましたCRUDメソッドを実装するビジネスレイヤークラスの抽象プロパティを持つコントロール。これにより、基本クラスからの「作成」、「読み取り」、「更新」、「削除」操作を自動化できました。静的な制限のため、シングルトンを使用する必要がありました。


1

ほとんどの人は、OOPクラスもオブジェクトであることを忘れているようです。そのため、メッセージがあり、何らかの理由でc#が「静的メソッド」を呼び出します。インスタンスオブジェクトとクラスオブジェクトの間に違いがあるという事実は、言語の欠陥または欠点のみを示しています。C#についての楽観主義者...


2
問題は、この質問が「in OOP」についてではないということです。「C#で」についてです。C#では、「メッセージ」はありません。
John Saunders、

1

ここに「typeメソッド」が必要な例があります。ソースXMLに基づいて、一連のクラスの1つを作成しています。だから私は

  static public bool IsHandled(XElement xml)

各クラスで順番に呼び出される関数。

それ以外の場合は不適切なオブジェクトの作成に時間を浪費するため、関数は静的でなければなりません。@Ian Boydeが指摘するように、これはファクトリクラスで実行できる可能性がありますが、これにより複雑さが増すだけです。

それをインターフェイスに追加して、クラスの実装者に強制的に実装させると便利です。これは大きなオーバーヘッドを引き起こしません-コンパイル/リンク時のチェックであり、vtableには影響しません。

ただし、これはかなり小さな改善でもあります。メソッドは静的であるため、呼び出し元である私はそれを明示的に呼び出す必要があるため、実装されていないとすぐにコンパイルエラーが発生します。インターフェイスで指定することを許可すると、このエラーは開発サイクルのわずかに早い段階で発生しますが、これは、他の壊れたインターフェイスの問題と比較すると簡単です。

したがって、これはマイナーな潜在的な機能であり、バランスをとるのがおそらく最善です。


1

静的クラスがC#で実装され、Microsoftが静的要素を含むクラスの特別なインスタンスを作成するという事実は、静的機能がどのように実現されるかの奇妙な点にすぎません。それは理論的なポイントではありません。

インターフェイスはクラスインターフェイスの記述子である必要があります-またはそれがどのように相互作用するか、そしてそれは静的な相互作用を含む必要があります。インターフェースの一般的な定義(Meriam-Websterから):さまざまなものが出会い、通信したり、相互に影響を及ぼしたりする場所または領域。クラスの静的コンポーネントまたは静的クラスを完全に省略した場合、これらのバッドボーイの相互作用の大部分は無視されます。

以下は、静的クラスを持つインターフェースを使用できることが非常に役立つ場合の非常に明確な例です。

public interface ICrudModel<T, Tk>
{
    Boolean Create(T obj);
    T Retrieve(Tk key);
    Boolean Update(T obj);
    Boolean Delete(T obj);
}

現在、私はこれらのメソッドを含む静的クラスを作成し、何もチェックせずに、何も忘れていないことを確認しています。OOPの前のプログラミングの悪い昔のようなものです。


これは古代の質問です。最近では、意見に基づく質問は信頼できる回答が難しいため、回避するように努めています。これに答える唯一の良い方法は、MSが彼らがした方法でそれをするためにMSが持っていた、または明らかに持っているべきだった理由を説明することです。
Nathan Tuggy 2015

1

C#とCLRは、Javaと同様に、インターフェイスで静的メソッドをサポートする必要があります。static修飾子はコントラクト定義の一部であり、特に呼び出しや呼び出しによって異なる場合がありますが、動作や戻り値はインスタンスによって変化しないという意味があります。

とはいえ、インターフェースで静的メソッドを使用したいが使用できない場合は、代わりにアノテーションを使用することをお勧めします。あなたが探している機能が手に入ります。


0

簡単に言えば、「役に立たないから」です。インターフェイスメソッドを呼び出すには、型のインスタンスが必要です。インスタンスメソッドから、必要な静的メソッドを呼び出すことができます。


0

問題は、まさにこのような状況のために、C#には別のキーワードが必要であるという事実に達していると思います。戻り値が呼び出されるタイプにのみ依存するメソッドが必要です。型が不明な場合は、「静的」とは言えません。しかし、型が判明すると、静的になります。「未解決の静的」という考え方です-まだ静的ではありませんが、受け取り側のタイプが分かれば、静的になります。これは完全に優れた概念であり、プログラマが求め続けているのはこのためです。しかし、それはデザイナーが言語について考える方法に完全に適合しませんでした。

利用できないので、以下に示す方法で非静的メソッドを使用することにしました。厳密には理想的ではありませんが、少なくとも私にとっては、より意味のあるアプローチを見つけることができません。

public interface IZeroWrapper<TNumber> {
  TNumber Zero {get;}
}

public class DoubleWrapper: IZeroWrapper<double> {
  public double Zero { get { return 0; } }
}

0

オブジェクト指向の概念によると、クラスによって実装されたインターフェースと、オブジェクトを使用してこれらの実装された関数(またはメソッド)にアクセスする契約があります。

したがって、インターフェイスコントラクトメソッドにアクセスする場合は、オブジェクトを作成する必要があります。Staticメソッドの場合、常に許可されていない必要があります。静的クラス、メソッド、変数はオブジェクトを必要とせず、その領域(またはクラス)のオブジェクトを作成せずにメモリにロードするか、オブジェクト作成を必要としないと言えます。


0

概念的には、インターフェイスが静的メソッドを含むコントラクトを定義できなかった理由はありません。

現在のC#言語の実装では、制限は基本クラスとインターフェイスの継承が許可されているためです。「クラスSomeBaseClass」が「インターフェースISomeInterface」を実装し、「クラスSomeDerivedClass:SomeBaseClass、ISomeInterface」もインターフェースを実装する場合、静的メソッドがインスタンスメソッドと同じシグネチャを持つことができないため、インターフェースメソッドを実装する静的メソッドはコンパイルに失敗します(これにより、インターフェイスを実装するために基本クラスに存在する必要があります)。

静的クラスは、機能的にはシングルトンと同じであり、構文が簡潔なシングルトンと同じ目的を果たします。シングルトンはインターフェースを実装できるため、静的によるインターフェース実装は概念的に有効です。

つまり、継承全体で同じ名前のインスタンスと静的メソッドのC#名の競合の制限に要約されます。静的メソッドコントラクト(インターフェイス)をサポートするためにC#を "アップグレード"できない理由はありません。


-1

クラスがインターフェースを実装すると、インターフェースメンバーのインスタンスが作成されます。静的型にはインスタンスがありませんが、インターフェイスに静的シグネチャを設定しても意味がありません。

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