// Exercise 1: own and dispose resources correctly (easy) // // FakeConnection simulates an unmanaged resource: it increments OpenCount when created and // decrements it when disposed. Disposing twice must not decrement twice. // // Implement: // - FakeConnection.Dispose(): idempotent (only the first call decrements OpenCount). // - Repository: OWNS a FakeConnection it creates in its constructor, so it must implement IDisposable // and dispose the connection in Dispose(). // - CountRows(n): opens `n` repositories one at a time with `using` so that none remain open afterwards, // returning the sum of repo.Rows(). // // Run with: dotnet run (inside a console project). using System; class FakeConnection : IDisposable { public static int OpenCount; public FakeConnection() { OpenCount++; } public void Dispose() { // TODO: decrement OpenCount only once } } class Repository : IDisposable { readonly FakeConnection _conn = new FakeConnection(); public int Rows() => 10; public void Dispose() { // TODO: dispose the connection we own } } class Program { static int CountRows(int n) { int total = 0; for (int i = 0; i < n; i++) { var repo = new Repository(); // TODO: make sure it's disposed total += repo.Rows(); } return total; } 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 c = new FakeConnection(); c.Dispose(); c.Dispose(); Check("Dispose is idempotent", FakeConnection.OpenCount == 0); Check("CountRows sums rows", CountRows(5) == 50); Check("no connections left open", FakeConnection.OpenCount == 0); try { using var r = new Repository(); throw new InvalidOperationException(); } catch (InvalidOperationException) { } Check("disposed even when an exception is thrown", FakeConnection.OpenCount == 0); Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }