// Exercise 2: avoid the event-handler memory leak (medium) // // A long-lived PriceFeed publishes price changes through an event. Short-lived widgets subscribe. // If they never unsubscribe, the feed keeps every widget alive forever (a classic managed leak). // // Implement: // - PriceFeed.Publish(price): raise PriceChanged safely (no NullReferenceException when nobody listens). // - PriceFeed.SubscriberCount: number of handlers currently attached (use GetInvocationList()). // - PriceWidget: subscribes in its constructor, stores the last price it saw, and unsubscribes in Dispose(). // // Run with: dotnet run (inside a console project). using System; class PriceFeed { public event EventHandler PriceChanged; public void Publish(decimal price) { // TODO: raise the event safely } public int SubscriberCount => 0; // TODO } class PriceWidget : IDisposable { readonly PriceFeed _feed; public decimal Last { get; private set; } public PriceWidget(PriceFeed feed) { _feed = feed; // TODO: subscribe } void OnPrice(object sender, decimal price) => Last = price; public void Dispose() { // TODO: unsubscribe } } class Program { static void Main() { int pass = 0, total = 0; void Check(string name, bool ok) { total++; if (ok) pass++; Console.WriteLine($"{(ok ? "PASS" : "FAIL")}: {name}"); } var feed = new PriceFeed(); bool threw = false; try { feed.Publish(1m); } catch (NullReferenceException) { threw = true; } Check("publishing with no subscribers is safe", !threw); var a = new PriceWidget(feed); var b = new PriceWidget(feed); feed.Publish(42.5m); Check("widgets receive prices", a.Last == 42.5m && b.Last == 42.5m); Check("two subscribers", feed.SubscriberCount == 2); a.Dispose(); feed.Publish(43m); Check("disposed widget no longer updated", a.Last == 42.5m && b.Last == 43m); Check("unsubscribed on dispose", feed.SubscriberCount == 1); for (int i = 0; i < 1000; i++) { using var w = new PriceWidget(feed); } Check("no leak after 1000 short-lived widgets", feed.SubscriberCount == 1); Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }