Utforska ombud och händelserelationer i C#

Slutförd

Händelser i C# bygger på delegater, som definierar metodsignaturen för händelsehanterare. Medan tidigare enheter introducerade grunderna för händelser och ombud fokuserar den här lektionen på avancerade begrepp, inklusive användning av EventHandler<T>, multicast-ombud och bästa praxis för att hantera komplexa händelsedrivna system.

När du fortsätter att utveckla butiksprogrammet fokuserar ditt team nu på att hantera mer komplexa scenarier, till exempel att meddela flera system när en betydande händelse inträffar eller skicka detaljerade händelsedata till prenumeranter. Genom att lära dig dessa begrepp kan du skapa robusta och underhållsbara program.

Avancerad Delegate-Event-relationskap

Delegater är typsäkra funktionspekare som gör det möjligt att skicka metoder som parametrar och anropa dem dynamiskt. Med andra ord fungerar ett ombud som ett "kontrakt" som anger metodens signatur, så att du kan skicka metoder runt som variabler. Händelser kapslar in delegater och ger ett strukturerat sätt att notifiera lyssnare när något betydande inträffar. I den här enheten utforskar vi hur man använder inbyggda delegater som EventHandler och EventHandler<T> för att förenkla händelsehanteringen.

Använda EventHandler<T> med anpassade händelsedata

Ombudet EventHandler<T> är ett inbyggt ombud som förenklar händelsehanteringen när anpassade händelsedata måste skickas till prenumeranter. Med den kan du definiera händelsehanterare som innehåller ytterligare information om händelsen.

Exempel: Använda EventHandler<T> med anpassade händelsedata

public class OrderEventArgs : EventArgs
{
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
}

public class OrderProcessor
{
    // Using EventHandler<T> to define an event with custom event data
    // Nullable to indicate no subscribers initially
    public event EventHandler<OrderEventArgs>? OrderProcessed; 

    protected virtual void OnOrderProcessed(OrderEventArgs e)
    {
        OrderProcessed?.Invoke(this, e);
    }

    public void ProcessOrder(int orderId)
    {
        Console.WriteLine($"Processing order {orderId}...");
        OnOrderProcessed(new OrderEventArgs
        {
            OrderId = orderId,
            OrderDate = DateTime.Now
        });
    }
}

// Subscribing to the event
public class Program
{
    public static void Main()
    {
        OrderProcessor processor = new OrderProcessor();
        processor.OrderProcessed += (sender, e) =>
        {
            Console.WriteLine($"Order {e.OrderId} processed on {e.OrderDate}");
        };

        processor.ProcessOrder(123); // Output: "Processing order 123..."
                                     // Output: "Order 123 processed on [current date and time]"
    }
}

I det här exemplet OrderProcessed deklareras händelsen som EventHandler<OrderEventArgs>?, med hjälp av en nullbar referenstyp. Referenstypen nullable anger uttryckligen att händelsen kanske inte har några prenumeranter, vilket säkerställer att koden hanterar sådana scenarier korrekt. Syntaxen ?.Invoke säkerställer att händelsen endast utlöses om det finns prenumeranter, vilket förhindrar potentiella NullReferenceException fel.

Lambda-uttryck, som visas i prenumerationen på OrderProcessed-händelsen, är ett standardsätt för att kortfattat definiera händelsehanterare inline.

Multicast-ombud

Multicast-delegat tillåter att flera metoder anropas i samband med en enskild händelse. Multicast-ombud är användbara när flera prenumeranter behöver svara på samma händelse, till exempel genom att meddela olika system eller komponenter.

Exempel: Använda multicast-delegater

public class NotificationService
{
    public event EventHandler? NotificationSent; // Nullable to indicate no subscribers initially

    public void SendNotification()
    {
        NotificationSent?.Invoke(this, EventArgs.Empty);
    }
}

public class Program
{
    public static void Main()
    {
        NotificationService service = new NotificationService();

        // Subscribing multiple methods to the event
        service.NotificationSent += (sender, e) => Console.WriteLine("Email notification sent!");
        service.NotificationSent += (sender, e) => Console.WriteLine("SMS notification sent!");

        service.SendNotification();
        // Output:
        // "Email notification sent!"
        // "SMS notification sent!"
    }
}

I det här exemplet används lambda-uttryck (=>) för att definiera händelsehanterare för NotificationSent händelsen. Lambda-uttryck påträffas ofta med delegater och ger ett kortfattat och läsbart sätt att definiera händelsehanterare, särskilt när varje hanterares logik är enkel.

Metodtips för att hantera händelser

Att hantera händelser effektivt är avgörande för att skapa robusta och underhållsbara program. Här följer några metodtips:

  • Undvik minnesläckor:

    Avbryt alltid prenumerationen på händelser när de inte längre behövs, särskilt om händelseutgivaren har en längre livslängd än prenumeranten.

  • Använd svaga referenser:

    I scenarier där prenumerantens livslängd är kortare än utgivarens bör du överväga att använda svaga referenser eller WeakEventManager för att undvika minnesläckor.

  • Säkerställ trådsäkerhet

    Om händelser genereras i en flertrådad miljö säkerställer du trådsäkerheten med hjälp av synkroniseringsmekanismer som lås eller trådsäkra samlingar.

Exempel: Avprenumerera för att undvika minnesläckor

public class Subscriber : IDisposable
{
    private readonly NotificationService _service;

    public Subscriber(NotificationService service)
    {
        _service = service;
        _service.NotificationSent += (sender, e) => Console.WriteLine("Notification received!");
    }

    public void Dispose()
    {
        _service.NotificationSent -= (sender, e) => Console.WriteLine("Notification received!");
    }
}

Sammanfattning

I den här lektionen har du utforskat avancerade begrepp för ombud och händelser i C#, inklusive:

  • Använda EventHandler<T> med anpassade händelsedata.
  • Använda lambda-uttryck för att förenkla händelsehanteringen.
  • Använda multicast-delegater för att meddela flera prenumeranter.
  • Metodtips för att hantera händelseprenumerationer, undvika minnesläckor och säkerställa trådsäkerhet.

Med dessa avancerade tekniker kan du skapa robusta, underhållsbara och skalbara händelsedrivna program.