2010-04-18 14 views

Respuesta

6

provoca un evento, se llame su caso manejador

que comenzó mal. Puede haber no controlador de eventos. O muchos. Tu no sabes Cuál es la diferencia principal de llamar un método directamente. Busque el "patrón de observador" en su libro de patrones de diseño favorito.

+0

Eso es todo! Gracias. – dotnetdev

2

provoca un evento (o Invocación, para usar el término de su enlace) significa que va a enviar el evento a todos los consumidores. Por ejemplo, una ventana puede generar un evento cuando se hace clic con el mouse.

El consumo de un evento significa que está recibiendo y procesando el evento de quien lo envió. Por ejemplo, es posible que desee saber cuándo se hace clic en la ventana con el mouse.

Si sólo tiene un consumidor, entonces se podría lograr algo similar con sólo el suministro de una devolución de llamada directa:

// 'Event' type: 
delegate void DelMyEvent(); 
// consumer: 
class Consumer 
{ 
    Producer _theProducer; 
    void RegisterForNotification() 
    { 
     _theProducer.OnMyEvent = new DelMyEvent(OnMyEvent); 
    } 
    void OnMyEvent() { } 
} 
// producer: 
class Producer 
{ 
    public DelMyEvent OnMyEvent; 
    void SendNotification() 
    { 
     if(OnMyEvent != null) OnMyEvent(); 
    } 
} 

El mecanismo de eventos limpia esto un poco por prevenir al consumidor de ajustar el valor de delegado directamente. En cambio, hace que el consumidor se registre con el operador +=. Cuando el primer consumidor se registra, el delegado se establece, y cuando el segundo consumidor se registra, sus dos devoluciones de llamadas se encadenan juntas por Delegate.Combine.

+0

"Si sólo tiene un consumidor, entonces se podría, en principio, utilizar un delegado en lugar de un evento", ¿por qué es un criterio para la selección de delegado sobre caso, incluso? ¡Muchos pueden registrarse para delegados! –

+1

Esta publicación es incorrecta. Un 'evento 'es simplemente un modificador, no un tipo. Un 'evento' es, de hecho, un' delegado' con algunas restricciones adicionales. La diferencia es que un evento no te permitirá configurarlo directamente. IE: 'myDelegate = someOtherDelegate;' le dará un error. Un evento restringe el acceso por lo que solo puede usar los operadores '+ =' y '- ='. Un delegado también puede tener una lista de invocaciones para hacer. Puede '+ =' tantos 'delegados' a un' delegado' como desee. Como puedes en un evento. – Joel

+0

Tienes razón. Han intentado arreglar el quebranto. – Eric

1

¿Cuál es la diferencia entre usar el mecanismo de eventos y llamadas directas a otros métodos (por ejemplo, si una condición es se reunió en el método A() llamada B())?

Business logic wise no hay diferencia entre los dos. Lo que quiero decir con esto es que puedes lograr la misma tarea en todos los sentidos. Es solo una forma diferente de hacerlo. La diferencia real es la cantidad de trabajo que tiene que hacer para manejar la notificación de otros módulos.

Al plantear un evento, básicamente estás diciendo "hey, ha ocurrido algo de código que se ha registrado para recibir una notificación cuando esto sucedió, házselo saber. Los módulos que se notifican no me conciernen, porque estoy asumiendo que (en tiempo de ejecución) todos los módulos que necesitan saber están configurados para la notificación ".

Al llamar a cada método directamente, está tomando la decisión de indicarle a este (o a estos) módulos, y solo a éstos, que algo ha ocurrido. Usted está haciendo esa afirmación de que no importa en qué estado se encuentren estos módulos no es importante y necesitan saber que sucedió este evento.

Ambos son correctos para diferentes situaciones. Las notificaciones de eventos son más dinámicas. Diferentes módulos pueden registrarse y cancelar el registro de notificaciones. Las llamadas a métodos directos son más estáticas.Un cierto conjunto de objetos (o módulos, etc.) serán absolutamente notificados (salvo excepciones por supuesto) de que algo sucedió, pero solo estos serán notificados.

0

Además de los escenarios de suscriptores múltiples/sin susodicho, los eventos también se usan para reducir el acoplamiento de códigos, por ejemplo, el método A() no necesita saber nada sobre el método B() en tiempo de compilación. Esto permite una mejor separación de preocupaciones y un código menos frágil.

En la naturaleza, es más probable que vea eventos usados ​​en el marco y código de UI, mientras que dentro de la lógica de dominio de una aplicación los desarrolladores utilizan más a menudo cosas como Separated Interface y Dependency Injection para desacoplar el código. Recientemente ha habido un poco más de discusión en varios ámbitos con respecto al uso de eventos dentro de la lógica del dominio, un enfoque que astutamente se llama Domain Events.

+1

Si bien generalmente es cierto que los eventos se usan para reducir el acoplamiento de códigos, creo que vale la pena señalar que a veces este no es el caso. De vez en cuando veo a los programadores usar eventos en lugar de llamadas a funciones directas porque creen que es mejor separar las preocupaciones, incluso cuando el evento está destinado a ser utilizado solo en una ubicación para llamar a una función. Terminas teniendo dos objetos acoplados que parecen objetos desacoplados para un observador casual. – tsiki

18

La diferencia es la siguiente:

llamada al método = "Haz esto cosa específica"

Evento elevar = "Si alguien está escuchando y se preocupa, esto acaba de suceder."

Es fundamental para la Separación de Preocupaciones y la reutilización. Un botón no es un componente reutilizable si al hacer clic en él se llama a un método específico. Pero si simplemente "anuncia" al programa que se hizo clic, y las partes interesadas son responsables de suscribirse a eso, es infinitamente reutilizable.

La implementación técnica subyacente de cómo se realiza esto (a través del delegado) es irrelevante.

2

Para cualquiera que esté interesado en la realización de llamadas de eventos, he hecho este sencillo punto de referencia. Muestra las diferencias entre llamar a un método directamente, llamarlo a través de la interfaz, a través de un delegado y a través de un evento, donde se adjunta un controlador.

En cada escenario, el método se llama de manera correspondiente 1 000 000 000 veces. Aquí hay resultados (tal vez sorprendentes):

llamada Delegado: 23 240 ms - el más rápido de llamadas

Evento: 23 295 ms

llamada directa: 23 396 ms

llamada

Interfaz: 23 716 ms - el más lento

Las medidas se realizaron en la compilación de lanzamiento usando C# en .NET4.0.

El código está aquí:

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestClass.RunTest(); 
     Console.ReadLine(); 
    } 
} 

interface ITestClass 
{ 
    void TestMethod(object sender, TestEventArgs eventErgs); 
} 

class TestClass : ITestClass 
{ 
    #region Events 

    event EventHandler<TestEventArgs> TestEvent; 

    #endregion 

    #region Constructor 

    public TestClass() 
    { 
     TestEvent += TestMethod; 
    } 

    #endregion 

    #region Public Methods 

    public static void RunTest() 
    { 
     int testCount = 1000000000; //1 000 000 000 

     string format = "{0:### ### ### ##0}"; 

     #region Direct Call 

     Console.WriteLine("Direct call"); 
     TestClass testClass = new TestClass(); 

     testClass.TestMethod(testClass, new TestEventArgs(3)); 

     Stopwatch stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < testCount; ++i) 
     { 
      testClass.TestMethod(testClass, new TestEventArgs(3)); 
     } 
     stopwatch.Stop(); 
     Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds)); 
     Console.WriteLine(); 

     #endregion 

     #region Interface Call 

     Console.WriteLine("Interface call"); 
     ITestClass itestClass = new TestClass(); 
     itestClass.TestMethod(testClass, new TestEventArgs(3)); 

     stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < testCount; ++i) 
     { 
      itestClass.TestMethod(testClass, new TestEventArgs(3)); 
     } 
     stopwatch.Stop(); 
     Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds)); 
     Console.WriteLine(); 

     #endregion 

     #region Delegate Call 

     Console.WriteLine("Delegate call"); 
     TestClass delegateTestClass = new TestClass(); 
     Action<object, TestEventArgs> delegateMethod = delegateTestClass.TestMethod; 
     delegateMethod(testClass, new TestEventArgs(3)); 

     stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < testCount; ++i) 
     { 
      delegateMethod(testClass, new TestEventArgs(3)); 
     } 
     stopwatch.Stop(); 
     Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds)); 
     Console.WriteLine(); 

     #endregion 

     #region Event Call 

     Console.WriteLine("Event call"); 
     TestClass eventTestClast = new TestClass(); 
     eventTestClast.TestEvent(testClass, new TestEventArgs(3)); 

     stopwatch = Stopwatch.StartNew(); 
     for (int i = 0; i < testCount; ++i) 
     { 
      eventTestClast.TestEvent(testClass, new TestEventArgs(3)); 
     } 
     stopwatch.Stop(); 
     Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds)); 
     Console.WriteLine(); 

     #endregion 
    } 

    #endregion 

    #region ITestClass Members 

    public void TestMethod(object sender, TestEventArgs e) 
    { 
     e.Result = e.Value * 3; 
    } 

    #endregion 
} 

class TestEventArgs : EventArgs 
{ 
    public int Value { get; private set; } 

    public int Result { get; set; } 

    public TestEventArgs(int value) 
    { 
     Value = value; 
    } 
} 
Cuestiones relacionadas