0Pricing
C# Academy · Lezione

Pattern degli eventi, problemi comuni (memory leak)

Individuate e risolvete i problemi comuni degli eventi: annullate la sottoscrizione per evitare memory leak, conservate i riferimenti ai delegate per rimuoverli e usate un pattern di sottoscrizione con IDisposable.

Pattern degli eventi, problemi comuni (memory leak) è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 3 lezioni in totale.

Panoramica sulle insidie

Obiettivo: utilizzare gli eventi in modo sicuro.

  • Annulli la sottoscrizione per prevenire le perdite di memoria
  • Conservi un riferimento allo stesso gestore per poterlo rimuovere
  • Preferisca un piccolo pattern IDisposable per la pulizia
  • Eviti gestori anonimi inline che non può scollegare

Annullare la sottoscrizione per evitare perdite

Gli eventi conservano riferimenti ai sottoscrittori. Se il produttore vive a lungo e non si scollega mai il sottoscrittore, quest'ultimo non può essere raccolto dal garbage collector.

using System;

public class Publisher
{
  public event EventHandler Tick;
  public void Fire()
  {
    EventHandler h = Tick;
    if (h != null) h(this, EventArgs.Empty);
  }
}

public class Subscriber
{
  public void Handle(object s, EventArgs e)
  {
    Console.WriteLine("Handling tick");
  }

  public void Subscribe(Publisher p) { p.Tick += Handle; }
  public void Unsubscribe(Publisher p) { p.Tick -= Handle; } // required to avoid leaks
}

public class Program
{
  public static void Main(string[] args)
  {
    Publisher p = new Publisher();
    Subscriber s = new Subscriber();

    s.Subscribe(p);
    p.Fire();                // prints once

    s.Unsubscribe(p);        // detach when done
    s = null;                // now eligible for GC in a real app
    p.Fire();                // no output
  }
}

Conservare il riferimento al gestore

Per scollegare un gestore anonimo, lo memorizzi in una variabile e passi la stessa istanza a -=.

using System;

public class Button
{
  public event EventHandler Click;
  public void Simulate()
  {
    EventHandler h = Click;
    if (h != null) h(this, EventArgs.Empty);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    Button b = new Button();

    // BAD: cannot easily remove this later
    // b.Click += (s, e) => Console.WriteLine("inline");

    // GOOD: store the handler, attach, later detach the same instance
    EventHandler saved = (s, e) => Console.WriteLine("saved");
    b.Click += saved;

    b.Simulate();           // prints "saved"
    b.Click -= saved;       // can remove because we kept the reference
    b.Simulate();           // no output
  }
}

Sottoscrizione disposable

Restituisca un IDisposable da Subscribe. Utilizzi using per annullare automaticamente la sottoscrizione.

using System;

public class Ticker
{
  public event EventHandler Tick;

  public IDisposable Subscribe(EventHandler handler)
  {
    Tick += handler;
    return new Unsubscriber(this, handler);
  }

  private sealed class Unsubscriber : IDisposable
  {
    private Ticker _t;
    private EventHandler _h;
    private bool _done;

    public Unsubscriber(Ticker t, EventHandler h) { _t = t; _h = h; }

    public void Dispose()
    {
      if (!_done)
      {
        _t.Tick -= _h;
        _done = true;
      }
    }
  }

  public void Fire()
  {
    EventHandler h = Tick;
    if (h != null) h(this, EventArgs.Empty);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    Ticker t = new Ticker();
    using (t.Subscribe((s, e) => Console.WriteLine("tick")))
    {
      t.Fire(); // prints once
    }
    t.Fire();   // nothing after disposal
  }
}

Scollegare con try/finally

Utilizzi try/finally quando un gestore deve essere scollegato anche se viene generata un'eccezione.

using System;

public class Alarm
{
  public event EventHandler Ring;
  public void Trigger()
  {
    EventHandler h = Ring;
    if (h != null) h(this, EventArgs.Empty);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    Alarm a = new Alarm();
    EventHandler h = (s, e) => Console.WriteLine("ring");

    a.Ring += h;
    try
    {
      a.Trigger(); // do work with subscription active
    }
    finally
    {
      a.Ring -= h; // always detach
    }

    a.Trigger(); // no output
  }
}

Suggerimenti per evitare perdite

Suggerimenti:

  • I sottoscrittori dovrebbero gestire l'annullamento della propria sottoscrizione (Dispose, finally o un metodo esplicito).
  • Eviti di effettuare sottoscrizioni con gestori anonimi inline che non può rimuovere.
  • Presti attenzione agli eventi statici: spesso sopravvivono agli oggetti.
  • Mantenga brevi i gestori; non blocchi il produttore.

Causa delle perdite con gli eventi

Verifica rapida: qual è una causa comune delle perdite di memoria quando si utilizzano gli eventi C#?

Riepilogo

Riepilogo: annulli la sottoscrizione per prevenire le perdite, conservi i riferimenti ai gestori per poterli rimuovere e preferisca pattern di pulizia basati su disposable o finally per gestire in sicurezza il ciclo di vita degli eventi.

Domande Frequenti

La lezione «Pattern degli eventi, problemi comuni (memory leak)» è gratuita?

Sì — il testo completo di «Pattern degli eventi, problemi comuni (memory leak)» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 3 lezioni in totale.

Cosa imparerò in «Pattern degli eventi, problemi comuni (memory leak)»?

Individuate e risolvete i problemi comuni degli eventi: annullate la sottoscrizione per evitare memory leak, conservate i riferimenti ai delegate per rimuoverli e usate un pattern di sottoscrizione c… Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.

Quanto tempo richiede la lezione «Pattern degli eventi, problemi comuni (memory leak)»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. delegate, Action/Func, closure
  2. Eventi: pubblicazione/sottoscrizione, parola chiave event
  3. Pattern degli eventi, problemi comuni (memory leak)
← Torna a C# Academy