// Exercise 2: a thermostat with the standard event pattern (medium) // // Implement Thermostat: // - public event EventHandler? TemperatureChanged; // - public event EventHandler? Overheated; // - property Temperature { get; set; } — setting a DIFFERENT value raises // TemperatureChanged (with old + new values) through a // protected virtual OnTemperatureChanged(args) method. Setting the same // value raises nothing. // - when the new temperature crosses ABOVE Threshold (old <= Threshold, // new > Threshold), also raise Overheated — once per crossing, not on // every update while above. // - raise events null-safely (no subscribers must not throw). // // Then: in Main, notice the check that tries to unsubscribe a lambda. // Fix the subscription code (marked TODO in Main) so that the // unsubscribe actually works. // // Run with: dotnet run (inside a console project). using System; using System.Collections.Generic; record TemperatureChangedEventArgs(double Old, double New); class Thermostat { public double Threshold { get; } private double _temperature; public Thermostat(double initial, double threshold) { _temperature = initial; Threshold = threshold; } // TODO: declare the two events public double Temperature { get => _temperature; set { // TODO: compare, store, raise TemperatureChanged / Overheated _temperature = value; } } #pragma warning disable IDE0060 protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e) { // TODO } #pragma warning restore IDE0060 } class Program { static void Main() { int pass = 0, total = 0; var log = new List(); var t = new Thermostat(20, threshold: 30); // TODO (part 2): this subscription can't be removed later, because // `-=` below builds a brand-new lambda. Store the handler in a local // variable and use that variable for both += and -=. // t.TemperatureChanged += (s, e) => log.Add($"{e.Old}->{e.New}"); // t.Overheated += (s, e) => log.Add("HOT"); t.Temperature = 25; t.Temperature = 25; // same value: no event t.Temperature = 31; // crosses threshold t.Temperature = 35; // still above: no second HOT total++; string got = string.Join(" ", log); if (got == "20->25 25->31 HOT 31->35") { Console.WriteLine("PASS: events raised correctly"); pass++; } else Console.WriteLine("FAIL: log = " + got); // t.TemperatureChanged -= (s, e) => log.Add($"{e.Old}->{e.New}"); // TODO: replace with the stored handler log.Clear(); t.Temperature = 10; total++; if (log.Count == 0) { Console.WriteLine("PASS: handler unsubscribed"); pass++; } else Console.WriteLine("FAIL: handler still subscribed, log = " + string.Join(" ", log)); total++; try { new Thermostat(0, 1).Temperature = 5; Console.WriteLine("PASS: no subscribers is safe"); pass++; } catch (NullReferenceException) { Console.WriteLine("FAIL: raising with no subscribers threw"); } Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }