Como publicar eventos em conformidade com as Diretrizes do .NET (Guia de Programação em C#)

O procedimento a seguir demonstra como adicionar eventos que seguem o padrão .NET às suas classes e structs. Todos os eventos na biblioteca de classes do .NET são baseados no EventHandler delegado , que é definido da seguinte forma:

public delegate void EventHandler(object sender, EventArgs e);

Observação

.NET Framework 2.0 introduz uma versão genérica desse delegado, EventHandler<TEventArgs>. Os exemplos a seguir mostram como usar as duas versões.

Embora os eventos em classes que você define possam ser baseados em qualquer tipo delegado válido, mesmo delegados que retornam um valor, geralmente é recomendável que você basee seus eventos no padrão .NET EventHandlerusando , conforme mostrado no exemplo a seguir.

O nome EventHandler pode levar a um pouco de confusão, pois ele não trata realmente o evento. Os EventHandlergenéricos , e são EventHandler<TEventArgs> tipos delegados. Um método ou expressão lambda cuja assinatura corresponde à definição de delegado é o manipulador de eventos e será invocado quando o evento for gerado.

Publicar eventos com base no padrão EventHandler

  1. (Ignore esta etapa e vá para a Etapa 3a se você não tiver que enviar dados personalizados com seu evento.) Declare a classe para seus dados personalizados em um escopo visível para suas classes de editor e assinante. Em seguida, adicione os membros necessários para manter seus dados de evento personalizados. Neste exemplo, uma cadeia de caracteres simples é retornada.

    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }
    
        public string Message { get; set; }
    }
    
  2. (Ignore esta etapa se você estiver usando a versão genérica do EventHandler<TEventArgs>.) Declare um delegado em sua classe de publicação. Dê a ele um nome que termine com EventHandler. O segundo parâmetro especifica o tipo EventArgs personalizado.

    public delegate void CustomEventHandler(object sender, CustomEventArgs args);
    
  3. Declare o evento em sua classe de publicação, usando uma das etapas a seguir.

    1. Se você não tiver uma classe EventArgs personalizada, o tipo de evento será o delegado EventHandler não genérico. Você não precisa declarar o delegado porque ele já está declarado no namespace System que está incluído quando você cria seu projeto do C#. Adicione o seguinte código à sua classe publicadora.

      public event EventHandler RaiseCustomEvent;
      
    2. Se você estiver usando a versão não genérica de EventHandler e você tem uma classe personalizada derivada de EventArgs, declare o evento dentro de sua classe de publicação e use o delegado da etapa 2 como o tipo.

      public event CustomEventHandler RaiseCustomEvent;
      
    3. Se você estiver usando a versão genérica, não é necessário um delegado personalizado. Em vez disso, na sua classe de publicação, especifique o tipo de evento como EventHandler<CustomEventArgs>, substituindo o nome da sua própria classe entre os colchetes angulares.

      public event EventHandler<CustomEventArgs> RaiseCustomEvent;
      

Exemplo

O exemplo a seguir demonstra as etapas anteriores, usando uma classe EventArgs personalizada e o EventHandler<TEventArgs> como o tipo de evento.

using System;

namespace DotNetEvents
{
    // Define a class to hold custom event info
    public class CustomEventArgs : EventArgs
    {
        public CustomEventArgs(string message)
        {
            Message = message;
        }

        public string Message { get; set; }
    }

    // Class that publishes an event
    class Publisher
    {
        // Declare the event using EventHandler<T>
        public event EventHandler<CustomEventArgs> RaiseCustomEvent;

        public void DoSomething()
        {
            // Write some code that does something useful here
            // then raise the event. You can also raise an event
            // before you execute a block of code.
            OnRaiseCustomEvent(new CustomEventArgs("Event triggered"));
        }

        // Wrap event invocations inside a protected virtual method
        // to allow derived classes to override the event invocation behavior
        protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<CustomEventArgs> raiseEvent = RaiseCustomEvent;

            // Event will be null if there are no subscribers
            if (raiseEvent != null)
            {
                // Format the string to send inside the CustomEventArgs parameter
                e.Message += $" at {DateTime.Now}";

                // Call to raise the event.
                raiseEvent(this, e);
            }
        }
    }

    //Class that subscribes to an event
    class Subscriber
    {
        private readonly string _id;

        public Subscriber(string id, Publisher pub)
        {
            _id = id;

            // Subscribe to the event
            pub.RaiseCustomEvent += HandleCustomEvent;
        }

        // Define what actions to take when the event is raised.
        void HandleCustomEvent(object sender, CustomEventArgs e)
        {
            Console.WriteLine($"{_id} received this message: {e.Message}");
        }
    }

    class Program
    {
        static void Main()
        {
            var pub = new Publisher();
            var sub1 = new Subscriber("sub1", pub);
            var sub2 = new Subscriber("sub2", pub);

            // Call the method that raises the event.
            pub.DoSomething();

            // Keep the console window open
            Console.WriteLine("Press any key to continue...");
            Console.ReadLine();
        }
    }
}

Confira também