web-dev-qa-db-ja.com

ジェネリックスを使用したC#インターフェイスの静的メソッド呼び出し

これを実装する簡単な方法はありますか?可能であれば、オブジェクトをインスタンス化せずに:

interface I
{
     static  string GetClassName();
}

public class Helper
{

    static void PrintClassName<T>() where T : I
    {
         Console.WriteLine(T.GetClassName());
    }
}
28
Toto

代わりに拡張メソッドを試してください。

public interface IMyInterface
{
     string GetClassName();
}

public static class IMyInterfaceExtensions
{
    public static void PrintClassName<T>( this T input ) 
        where T : IMyInterface
    {
         Console.WriteLine(input.GetClassName());
    }
}

これにより、静的拡張/ユーティリティメソッドを追加できますが、それでもIMyInterface実装のインスタンスが必要です。

静的メソッドのインターフェイスは意味がないため使用できません。静的メソッドはインスタンスのないユーティリティメソッドであるため、実際には型がありません。

25
Keith

静的メソッドを継承することはできません。このため、インターフェイスに静的メソッドを設定できないため、コードはコンパイルされません。

littlegur から引用したように:

.NETでの継承は、インスタンスベースでのみ機能します。静的メソッドは、インスタンスレベルではなく、タイプレベルで定義されます。そのため、静的メソッド/プロパティ/イベントではオーバーライドが機能しません...

静的メソッドは、メモリに1回だけ保持されます。それらのために作成された仮想テーブルなどはありません。

.NETでインスタンスメソッドを呼び出す場合は、常に現在のインスタンスを指定します。これは.NETランタイムによって隠されていますが、発生します。各インスタンスメソッドには、最初の引数として、メソッドが実行されるオブジェクトへのポインタ(参照)があります。これは静的メソッドでは発生しません(タイプレベルで定義されているため)。 コンパイラはどのように呼び出すメソッドを選択する必要がありますか?

7
Dykam

また、少し前にインターフェイスに静的メソッドを設定しようとしましたが、理由はわかりません。私はこれをブックマークしたので、多分それは役立つでしょう:

拡張メソッドを使用した静的メソッドとのインターフェース

3
Nick Clarke

タイプ名の直後にいる場合は、次のようにすることができます。

public class Helper
{
    static void PrintClassName<T>()
    {
         Console.WriteLine(typeof(T).Name);
    }
}
3
Kent Boogaart

インターフェイス定義でstaticpropertyevent、またはmethodを宣言することは、正当な定義とは見なされません。これは、インターフェースがコントラクトと見なされ、そのため、そのインターフェースのすべてのクライアントインスタンスによって予定実装されるものを表すためです。

static宣言は、基本的に、staticメンバーが必要な機能を実行するために物理クライアントの実装を必要としないことを示しており、これはインターフェースの一般的な概念である実証済みのコントラクトの提供には達していません。

2
Mike J

答えは、修飾された「実際にはではなく、ソート」です。特定のインターフェイスのすべての実装者に静的拡張メソッドを提供し、プロパティまたは別のメソッドで実装者からこれを呼び出すことができます。例として:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InterfacesWithGenerics
{
    class Program
    {
        static void Main(string[] args)
        {
            Helper.PrintClassName<Example>(new Example());
            Console.ReadLine();
        }
    }

    public class Example : I
    {
        #region I Members

        public string ClassName
        {
            get { return this.GetClassName(); }
        }

        #endregion
    }

    public interface I
    {
        string ClassName { get; }
    }

    public class Helper
    {

        public static void PrintClassName<T>(T input) where T : I
        {           
            Console.WriteLine( input.GetClassName()) ;
        }
    }

    public static class IExtensions
    {
        public static string GetClassName(this I yourInterface)
        {
            return yourInterface.GetType().ToString();
        }
    }
}

ここには、関心のあるプロパティを定義するインターフェイス(I)と、必要な情報を取得するといううんざりする作業を行うそのタイプのすべてのメンバーに適用される静的拡張メソッド(GetClassName)があります。 Iインターフェイスを実装するクラス(Example)があるため、Exampleのインスタンスを渡す静的ヘルパークラスを呼び出すと、静的メソッドが実行されます。残念ながら、メソッド自体の中で型Tを変数として直接参照することは無効です。インスタンスを、アプリケーションに渡す必要があります。

1
Wolfwyrd

ClassNameを特定のクラスの属性として定義できます。これは、メタデータを.netに保存するための推奨されるayです。このようにして、特定のクラスの属性をクエリでき、インスタンスは必要ありません。

0
codymanix