2011-04-08 22 views
7

Quiero proporcionar a los objetos dentro de una biblioteca de clases la capacidad de "emitir" mensajes sin preocuparse por cómo se está produciendo. La biblioteca de clases se puede usar en una aplicación de consola, una aplicación de Windows WinForm o WPF, o una página web.¿Qué usar? delegar, evento o Func <T>?

Originalmente había decidido que usaría un delegado para manejar esto. Implementé esto usando clases pero al compilador no le gustó el delegado cuando intenté poner al delegado en una interfaz de la que es inherente cada uno de estos objetos.

Descubrí que podía mover al delegado fuera de la interfaz y luego pude compilar, pero no estoy seguro de que esto logre lo que estoy tratando de hacer ... También me parece un error, así que quería preguntar Si alguno de ustedes tiene ideas diferentes para lograr esto ...

La interfaz:

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage(string message); 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

a partir de ahí, no estoy seguro de cómo implementar este comportamiento: (Por cierto, sé que este código no se compilar ...)

public class ActionClass1 : IAction 
{ 
    // Other methods not shown... 
    void Execute() 
    { 
    if (this.DisplayMessage != null) 
    { 
     this.DisplayMessage(“Hello”); 
    } 
    } 
} 

public class ConsoleClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    class1.DisplayMessage = { x => Console.WriteLine(x); }; 
} 

public class WinFormClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    Class1.DisplayMessage = {x => DisplayTextBox.Text = x; }; 
} 

Respuesta

11

Si desea la capacidad de conectar varios delegados para responder a una sola llamada al Execute, definitivamente usaría un event. Si solo desea que se conecte una sola acción, use un delegado Action o Func.

Para su ejemplo, uno de los delegados Action debería funcionar. En su caso, sería Action<string> ya que su delegado toma un argumento de cadena. Un Action es simplemente un delegado que toma cero o más argumentos y devuelve vacío. Parece que no estás devolviendo nada, por eso sugiero Action.

Solo desea utilizar un Func<TResult> si su delegado necesita devolver algo. La diferencia entre Func y Action es que los delegados Func tienen un tipo de devolución y los delegados Action no. Cualquiera de estos delegados tiene versiones genéricas que pueden tomar hasta 16 o más argumentos.

Si necesita más de 16 argumentos de un delegado es posible que desee reconsiderar el diseño :)

+1

Cabe mencionar que si necesita algo más complicado que params, ref/out ... Acción/Func no funcionará. También otra 'gracia' es que puedes nombrar los parámetros de manera apropiada (intellisense). Dicho esto, también usaría la Acción . – Jake

1

Su definición de interfaz es erróneo. Debería especificarlo así:

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage { get; set; }; 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

y luego implementar la interfaz.

4

Puede hacerlo utilizando Action<string>.

No querrá usar Func<T>, ya que esto define a un delegado que no toma argumentos pero devuelve un solo valor de tipo T. Action<T>, por otro lado, es un delegado que toma un solo argumento de tipo T.

sugeriría probar:

public interface IAction 
{ 
    Action<string> DisplayMessage { get; set; } 

    void Execute(); 
    XElement Serialize(XName elementName); 
} 

Una vez que ha implementado esta interfaz (completamente), se podría utilizar a través de:

public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = x => Console.WriteLine(x); 
    } 
} 

O:

public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = this.Print; 
    } 

    private void Print(string message) 
    { 
     Console.WriteLine(message); 
    } 
} 

que podría hacer lo mismo con los eventos, sin embargo, cuestionaría esto. Su API describe una acción que debería ocurrir, no un evento que está sucediendo al que está respondiendo, y como tal, no recomendaría un evento.

1

Aquí

DisplayMessageDelegate DisplayMessage(string message); 

que describa el método que acepte cadena y devuelve DisplayMessageDelegate. Uso

event DisplayMessageDelegate DisplayMessage; 

lugar.

0

Personalmente, hubiera pensado que sería mejor tener una clase base abstracta que definiera un método abstracto llamado DisplayMessage y luego extender esa clase base derivando de ella para alterar el comportamiento de la forma en que se muestran los mensajes.

+0

Considero que ... dejé fuera el hecho (en un intento de simplificar el problema) de que estas clases derivadas estuvieran en una colección List donde haría un ciclo ForEach para ejecutar el método Execute para cada elemento, configuración el "DisplayMessage" basado en el tipo de aplicación que estoy ejecutando en ese momento ... –

0

En lugar de:

DisplayMessageDelegate DisplayMessage(string message); 

Do:

event Action<string> DisplayMessage; 

continuación, utilizar el DisplayMessage por la normalidad, los eventos son delegados.

Cuestiones relacionadas