web-dev-qa-db-ja.com

デリゲートをインターフェイスに配置できないのはなぜですか?

インターフェイスにデリゲートを追加できないのはなぜですか?

27
user73936

次のいずれかを使用できます。

public delegate double CustomerDelegate(int test);
public interface ITest
{
    EventHandler<EventArgs> MyHandler{get;set;}
    CustomerDelegate HandlerWithCustomDelegate { get; set; }
    event EventHandler<EventArgs> MyEvent;
}
33
eglasius

Delegateは単なる別のタイプであるため、インターフェイス内に配置しても何も得られません。

独自のデリゲートを作成する必要はありません。ほとんどの場合、EventHandler、Func、Predicate、またはActionを使用する必要があります。

デリゲートがどのように見えるか聞いてもいいですか。

24
Jonathan Allen

Delegatetype であり、インターフェイスで宣言することはできません。イベント(適切な場合)を使用するか、インターフェイスの外でデリゲートを宣言しますが、同じ名前空間で行います。

このリンクが役立つ場合があります- インターフェイスの代わりにデリゲートを使用する場合

7
cgreeno

これはデリゲートTYPEデカラレーションです...

public delegate returntype MyDelegateType (params)

これは型宣言なので、インターフェースで宣言できません

ただし、上記の型宣言を使用すると、デリゲートインスタンスを使用できます

MyDelegateType MyDelegateInstance ( get; set;)

したがって、デリゲートインスタンスは問題ありませんが、デリゲート型宣言は(インターフェイスでは)できません

6
Matt

ドキュメントには、インターフェイスでデリゲートを定義できることが明記されています。

インターフェイスには、メソッド、デリゲート、またはイベントのシグネチャのみが含まれます。

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

ただし、同じページの備考では、インターフェイスにはメソッド、プロパティ、インデクサー、およびイベントのシグネチャを含めることができると記載されています。

デリゲートをインターフェイスに配置しようとすると、コンパイラは「インターフェイスは型を宣言できない」と言います。

Ecma-334標準(8.9インターフェース)は、そのページとコンパイラーの注釈に同意します。

4
Guffa

他の人が述べたように、インターフェースのデリゲートoutsideのみを定義できます。

デリゲートを使用する場合、問題はほとんどありません。個人的にはFunc<int, double>はデリゲートを使用するよりも望ましくありません。

  1. 引数に名前を付けることはできないため、引数の意味があいまいになる可能性があります
  2. イベントはスレッドセーフではないため、次のコードは理想的ではありません。

    if (MyFuncEvent != null)
    {
        MyFuncEvent(42, 42.42);
    }
    

    参照: http://kristofverbiest.blogspot.com/2006/08/better-way-to-raise-events.html

    より安全なコードは次のとおりです。

    MyFuncEventHandler handler = MyFuncEvent;
    if (handler != null)
    {
        handler(42, 42.42);
    }
    
  3. 変数に保存する場合は、イベントの署名を複製する必要があります(または、varを使用することもできますが、これは嫌いです)。引数が多い場合、これは非常に退屈になる可能性があります(繰り返しますが、いつも怠惰でvarを使用できます)。

    Func<int, double, string, object, short, string, object> handler = MyFuncEvent;
    if (handler != null)
    {
        handler(42, 42.42, ...);
    }
    

デリゲートを使用すると、変数タイプに割り当てるたびにメソッド/イベントのシグネチャを複製する必要がなくなります。

1
swooby

インターフェイスメソッドはデリゲートをパラメーターとして受け入れることができ、問題はありません。 (多分私は問題を見ていませんか?)しかし、意図がインターフェースでアウトバウンドコールを指定することであるならば、イベントを使用してください。

細かいことはたくさんあるので、すべてを散文で説明するのではなく、コードを表示する方がはるかに簡単です。 (申し訳ありませんが、コードサンプルでも少し肥大化しています...)

namespace DelegatesAndEvents
{
    public class MyEventArgs : EventArgs
    {
        public string Message { get; set; }
        public MyEventArgs(string message) { Message = message; }
    }

    delegate void TwoWayCallback(string message);
    delegate void TwoWayEventHandler(object sender, MyEventArgs eventArgs);

    interface ITwoWay
    {
        void CallThis(TwoWayCallback callback);

        void Trigger(string message);
        event TwoWayEventHandler TwoWayEvent;
    }

    class Talkative : ITwoWay
    {
        public void CallThis(TwoWayCallback callback)
        {
            callback("Delegate invoked.");
        }

        public void Trigger(string message)
        {
            TwoWayEvent.Invoke(this, new MyEventArgs(message));
        }

        public event TwoWayEventHandler TwoWayEvent;
    }

    class Program
    {
        public static void MyCallback(string message)
        {
            Console.WriteLine(message);
        }

        public static void OnMyEvent(object sender, MyEventArgs eventArgs)
        {
            Console.WriteLine(eventArgs.Message);
        }

        static void Main(string[] args)
        {
            Talkative talkative = new Talkative();

            talkative.CallThis(MyCallback);

            talkative.TwoWayEvent += new TwoWayEventHandler(OnMyEvent);
            talkative.Trigger("Event fired with this message.");

            Console.ReadKey();
        }
    }
}
0
Paul Williams