รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)
ตรวจหาและแก้ไขข้อควรระวังเกี่ยวกับเหตุการณ์: ยกเลิกการสมัครรับเพื่อป้องกันหน่วยความจำรั่ว เก็บการอ้างอิง 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 เพราะมักมีอายุยืนยาวกว่าออบเจ็กต์
- ทำให้ตัวจัดการสั้น และอย่าบล็อกผู้เผยแพร่
สาเหตุของการรั่วไหลจากเหตุการณ์
ทบทวน
ทบทวน: ยกเลิกการสมัครรับเพื่อป้องกันการรั่วไหล เก็บการอ้างอิงของตัวจัดการเพื่อถอดออก และเลือกใช้รูปแบบการทำความสะอาดด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- delegate, Action/Func, คลอสเชอร์
- เหตุการณ์: การเผยแพร่/การสมัครรับ คีย์เวิร์ด event
- รูปแบบเหตุการณ์และข้อควรระวัง (หน่วยความจำรั่ว)