2009-03-04 27 views

Respuesta

23

Un delegado es simplemente otro tipo, por lo que no se gana nada al ponerlo dentro de la interfaz.

No debería necesitar crear sus propios delegados. La mayoría de las veces debe usar EventHandler, Func, Predicate o Action.

¿Puedo preguntar cómo es tu delegado?

+2

No veo por qué alguien establecer un voto negativo ... – eglasius

+2

Esta respuesta en realidad también resolvió mi problema que nunca pude encontrar una buena manera de utilizar delegados en las situaciones en las que quería usarlos. Es decir. no use 'm :). –

31

Puede utilizar cualquiera de estos:

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

¿Por qué crear CustomerDelegate cuando puede usar Func ? –

+1

que sé, sólo estaba ilustrando que se puede utilizar casi cualquier cosa :) – eglasius

+8

Se hace difícil entender como parámetros Func . Mucho más significativo tener un nombre para esa firma. – diachedelic

4

La documentación dice claramente que se puede definir un delegado en una interfaz:

Una interfaz contiene sólo los firmas de los métodos, los delegados o eventos.

MSDN: interface (C# Reference)

Sin embargo, en los comentarios en la misma página se dice que una interfaz puede incluir firmas de métodos, propiedades y eventos indexadores.

Si intenta poner un delegado en una interfaz, el compilador dice que "las interfaces no pueden declarar tipos".

El estándar Ecma-334 (8.9 Interfaces) está de acuerdo con los comentarios en esa página y en el compilador.

+2

Parece un error en MSDN. Eso debería ser "las firmas de métodos, propiedades o eventos", ¿no es así? – configurator

6

este es un decalaration delegado TIPO ...

public delegate returntype MyDelegateType (params) 

esto no puede ser declarado en una interfaz, ya que es una declaración de tipo

sin embargo con la declaración de tipo de arriba se puede utilizar una instancia de delegado

MyDelegateType MyDelegateInstance (get; set;) 

tan delegar casos están bien, pero tipo de delegado declaraciones no son (en una interfaz)

+0

La mejor respuesta hasta el momento. Al punto. Me encanta cuando las personas van al grano en lugar de escribir discursos. – DavidGuaita

1

Como han mencionado otros, solo puede definir delegados fuera de de la interfaz.

No hay nada malo con los delegados. personalmente creo que Func<int, double> es menos deseable que utilizan delegados:

  1. No se puede nombrar a los argumentos, por lo que el significado argumento puede ser ambigua
  2. Es noticia vieja que los acontecimientos no es seguro para subprocesos, por lo tanto el siguiente código no es ideal:

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

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

    El código más seguro es:

    MyFuncEventHandler handler = MyFuncEvent; 
    if (handler != null) 
    { 
        handler(42, 42.42); 
    } 
    
  3. Usted tiene que duplicar la firma del evento si desea guardarla en una variable (o puede utilizar var, lo que me gusta). Si tiene muchos argumentos, esto puede ser muy tedioso (nuevamente, siempre puede ser flojo y usar var).

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

Los delegados se salvan de tener que duplicar la firma del método/evento cada vez que desee asignar a un tipo variable.

+0

Sin embargo, tenga en cuenta que el nombre _es los argumentos en el sitio llamado de una función lambda (pero sólo si hay más de dos): Acción f = (int i, int j) => {}; /* mismo que, */ var g = (Acción ) ((i, j) => {}); Curiosamente, no se puede usar 'var' cuando se utiliza la sintaxis anterior (que es cuando menos se necesita). –

+0

¡Es bueno saberlo! – swooby

0

Un método de interfaz puede aceptar un delegado como parámetro, no hay problemas. (¿Tal vez no veo el problema?) Pero si la intención es especificar una llamada saliente en la interfaz, use un evento.

Hay tantos pequeños detalles, que es mucho más fácil mostrar sólo algunas código en lugar de tratar de describir todo en prosa. (Lo siento, incluso el ejemplo de código es un poco hinchado ...)

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