0Pricing
C# Academy · บทเรียน

รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)

ตรวจหาและแก้ไขข้อควรระวังเกี่ยวกับเหตุการณ์: ยกเลิกการสมัครรับเพื่อป้องกันหน่วยความจำรั่ว เก็บการอ้างอิง delegate ไว้เพื่อนำออก และใช้รูปแบบการสมัครรับด้วย IDisposable

รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว) เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน

ภาพรวมของข้อผิดพลาดที่พบบ่อย

เป้าหมาย: ใช้เหตุการณ์อย่างปลอดภัย

  • ยกเลิกการสมัครรับเพื่อป้องกัน การรั่วไหลของหน่วยความจำ leaks
  • เก็บการอ้างอิงไปยัง ตัวจัดการเดียวกัน เพื่อถอดการเชื่อมต่อ
  • เลือกใช้รูปแบบ IDisposable ขนาดเล็กเพื่อทำความสะอาด
  • หลีกเลี่ยงตัวจัดการไม่ระบุชื่อแบบแทรกในบรรทัดที่ไม่สามารถถอดการเชื่อมต่อได้

ยกเลิกการสมัครรับเพื่อหลีกเลี่ยงการรั่วไหล

เหตุการณ์จะเก็บการอ้างอิงไปยังผู้สมัครรับ หากผู้เผยแพร่มีอายุการใช้งานยาวนานและคุณไม่เคยถอดการเชื่อมต่อ ผู้สมัครรับก็จะไม่สามารถถูกเก็บคืนได้

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
  }
}

เก็บการอ้างอิงของตัวจัดการ

หากต้องการถอดตัวจัดการไม่ระบุชื่อ ให้เก็บตัวจัดการนั้นไว้ในตัวแปร แล้วส่งอินสแตนซ์เดิมให้กับ -=

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
  }
}

การสมัครรับแบบทำลายได้

ส่งคืน IDisposable จาก Subscribe ใช้ using เพื่อยกเลิกการสมัครรับโดยอัตโนมัติ

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
  }
}

ถอดการเชื่อมต่อด้วย try/finally

ใช้ try/finally เมื่อต้องถอดการเชื่อมต่อตัวจัดการแม้ว่าจะเกิดข้อยกเว้นขึ้นก็ตาม

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
  }
}

เคล็ดลับเพื่อหลีกเลี่ยง leaks

เคล็ดลับ:

  • ผู้สมัครรับควรรับผิดชอบการยกเลิกการสมัครรับของตนเอง (Dispose, finally หรือเมธอดที่เรียกใช้โดยชัดเจน)
  • หลีกเลี่ยงการสมัครรับด้วยตัวจัดการไม่ระบุชื่อแบบแทรกในบรรทัดที่ไม่สามารถถอดออกได้
  • ระวังเหตุการณ์แบบ static เพราะมักมีอายุยืนยาวกว่าออบเจ็กต์
  • ทำให้ตัวจัดการสั้น และอย่าบล็อกผู้เผยแพร่

สาเหตุของการรั่วไหลจากเหตุการณ์

ตรวจสอบอย่างรวดเร็ว: สาเหตุทั่วไปของการรั่วไหลของหน่วยความจำเมื่อใช้เหตุการณ์ C# คืออะไร

ทบทวน

ทบทวน: ยกเลิกการสมัครรับเพื่อป้องกันการรั่วไหล เก็บการอ้างอิงของตัวจัดการเพื่อถอดออก และเลือกใช้รูปแบบการทำความสะอาดด้วย IDisposable หรือ finally เพื่อจัดการอายุการใช้งานของเหตุการณ์อย่างปลอดภัย

คำถามที่พบบ่อย

บทเรียน “รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)”

ตรวจหาและแก้ไขข้อควรระวังเกี่ยวกับเหตุการณ์: ยกเลิกการสมัครรับเพื่อป้องกันหน่วยความจำรั่ว เก็บการอ้างอิง delegate ไว้เพื่อนำออก และใช้รูปแบบการสมัครรับด้วย IDisposable คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน

บทเรียน “รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. delegate, Action/Func, คลอสเชอร์
  2. เหตุการณ์: การเผยแพร่/การสมัครรับ คีย์เวิร์ด event
  3. รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)
← กลับไปที่ C# Academy