Почему я не могу поместить делегата в интерфейс? - PullRequest
27 голосов
/ 05 марта 2009

Почему я не могу добавить делегата в свой интерфейс?

Ответы [ 7 ]

33 голосов
/ 05 марта 2009

Вы можете использовать любой из них:

public delegate double CustomerDelegate(int test);
public interface ITest
{
    EventHandler<EventArgs> MyHandler{get;set;}
    CustomerDelegate HandlerWithCustomDelegate { get; set; }
    event EventHandler<EventArgs> MyEvent;
}
24 голосов
/ 05 марта 2009

Делегат - это просто другой тип, поэтому вы ничего не получите, поместив его в интерфейс.

Вам не нужно создавать своих собственных делегатов. В большинстве случаев вам просто нужно использовать EventHandler, Func, Predicate или Action.

Могу я спросить, как выглядит ваш делегат?

7 голосов
/ 05 марта 2009

A Делегат - это тип , который нельзя объявить в интерфейсе. Возможно, вы захотите использовать событие (при необходимости) или объявить делегата за пределами интерфейса, но в том же пространстве имен.

Эта ссылка может помочь - Когда использовать делегаты вместо интерфейсов

6 голосов
/ 05 марта 2009

это делегирование ТИПА делегата ...

public delegate returntype MyDelegateType (params)

это не может быть объявлено в интерфейсе, так как это объявление типа

однако, используя приведенное выше объявление типа, вы МОЖЕТЕ использовать экземпляр делегата

MyDelegateType MyDelegateInstance ( get; set;)

поэтому экземпляры делегатов в порядке, а объявления типов делегатов - нет (в интерфейсе)

4 голосов
/ 05 марта 2009

В документации четко сказано, что вы можете определить делегата в интерфейсе:

Интерфейс содержит только подписи методов, делегатов или события.

MSDN: интерфейс (C # Reference)

Однако в комментариях на той же странице говорится, что интерфейс может содержать подписи методов, свойств, индексаторов и событий.

Если вы попытаетесь поместить делегата в интерфейс, компилятор скажет, что «интерфейсы не могут объявлять типы».

Стандарт Ecma-334 (8.9 Interfaces) согласуется с замечаниями на этой странице и компилятором.

1 голос
/ 27 апреля 2012

Как уже упоминалось, вы можете определять только делегатов вне интерфейса.

Нет ничего плохого в том, чтобы использовать делегатов. Лично я считаю, что 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, ...);
    }
    

Делегаты избавляют вас от необходимости дублировать подпись метода / события каждый раз, когда вы хотите присвоить ее типу переменной.

0 голосов
/ 21 ноября 2012

Метод интерфейса может принимать делегата в качестве параметра, никаких проблем. (Может быть, я не вижу проблемы?) Но если вы хотите указать исходящий вызов в интерфейсе, используйте событие.

Существует так много мелких деталей, что гораздо проще просто показать какой-то код, чем пытаться описать все это в прозе. (Извините, даже пример кода немного раздут ...)

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();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...