Dispose-Template.txt ---------- 2017-04-15 // http://svc.luckstar.com.tw/CodeHelper/cs/index.html // 2017-04-15, honda@luckstar.com.tw, Create for demo dispose template. e.g. Implement CSqlClient usage. // Please ref to: // CSqlClient.cs.txt, // CDBPubs.cs.txt, // CDBNorthwind.cs.txt, // CRunSqlClient.cs.tx // and Dispose-Template.txt ref: https://msdn.microsoft.com/zh-tw/library/b1yfkh5e(v=vs.100).aspx ---------- // Design pattern for a base class. public class Base: IDisposable { private bool disposed = false; // To detect redundant calls //Implement IDisposable. public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free other state (managed objects). } // Free your own state (unmanaged objects). // Set large fields to null. // Call dispose on your base class. // base.Dispose(disposing); disposed = true; } } // Use C# destructor syntax for finalization code. ~Base() { // Simply call Dispose(false). Dispose (false); } } // Design pattern for a derived class. public class Derived: Base { private bool disposed = false; protected override void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Release managed resources. } // Release unmanaged resources. // Set large fields to null. // Call Dispose on your base class. disposed = true; } base.Dispose(disposing); } // The derived class does not have a Finalize method // or a Dispose method without parameters because it inherits // them from the base class. } ---------- //Design pattern for a base class. // AND //Design pattern for a derived class using System; using System.Collections.Generic; using System.Runtime.InteropServices; // Design pattern for a base class. public abstract class Base : IDisposable { private bool disposed = false; private string instanceName; private List trackingList; public Base(string instanceName, List tracking) { this.instanceName = instanceName; trackingList = tracking; trackingList.Add(this); } public string InstanceName { get { return instanceName; } } //Implement IDisposable. public void Dispose() { Console.WriteLine("\n[{0}].Base.Dispose()", instanceName); Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free other state (managed objects). Console.WriteLine("[{0}].Base.Dispose(true)", instanceName); trackingList.Remove(this); Console.WriteLine("[{0}] Removed from tracking list: {1:x16}", instanceName, this.GetHashCode()); } else { Console.WriteLine("[{0}].Base.Dispose(false)", instanceName); } disposed = true; } } // Use C# destructor syntax for finalization code. ~Base() { // Simply call Dispose(false). Console.WriteLine("\n[{0}].Base.Finalize()", instanceName); Dispose(false); } } // Design pattern for a derived class. public class Derived : Base { private bool disposed = false; private IntPtr umResource; public Derived(string instanceName, List tracking) : base(instanceName, tracking) { // Save the instance name as an unmanaged resource umResource = Marshal.StringToCoTaskMemAuto(instanceName); } protected override void Dispose(bool disposing) { if (!disposed) { if (disposing) { Console.WriteLine("[{0}].Derived.Dispose(true)", InstanceName); // Release managed resources. } else { Console.WriteLine("[{0}].Derived.Dispose(false)", InstanceName); } // Release unmanaged resources. if (umResource != IntPtr.Zero) { Marshal.FreeCoTaskMem(umResource); Console.WriteLine("[{0}] Unmanaged memory freed at {1:x16}", InstanceName, umResource.ToInt64()); umResource = IntPtr.Zero; } disposed = true; } // Call Dispose in the base class. base.Dispose(disposing); } // The derived class does not have a Finalize method // or a Dispose method without parameters because it inherits // them from the base class. } public class TestDisposal { public static void Main() { List tracking = new List(); // Dispose is not called, Finalize will be called later. using (null) { Console.WriteLine("\nDisposal Scenario: #1\n"); Derived d3 = new Derived("d1", tracking); } // Dispose is implicitly called in the scope of the using statement. using (Derived d1 = new Derived("d2", tracking)) { Console.WriteLine("\nDisposal Scenario: #2\n"); } // Dispose is explicitly called. using (null) { Console.WriteLine("\nDisposal Scenario: #3\n"); Derived d2 = new Derived("d3", tracking); d2.Dispose(); } // Again, Dispose is not called, Finalize will be called later. using (null) { Console.WriteLine("\nDisposal Scenario: #4\n"); Derived d4 = new Derived("d4", tracking); } // List the objects remaining to dispose. Console.WriteLine("\nObjects remaining to dispose = {0:d}", tracking.Count); foreach (Derived dd in tracking) { Console.WriteLine(" Reference Object: {0:s}, {1:x16}", dd.InstanceName, dd.GetHashCode()); } // Queued finalizers will be exeucted when Main() goes out of scope. Console.WriteLine("\nDequeueing finalizers..."); } } // The program will display output similar to the following: // // Disposal Scenario: #1 // // // Disposal Scenario: #2 // // // [d2].Base.Dispose() // [d2].Derived.Dispose(true) // [d2] Unmanaged memory freed at 000000000034e420 // [d2].Base.Dispose(true) // [d2] Removed from tracking list: 0000000002bf8098 // // Disposal Scenario: #3 // // // [d3].Base.Dispose() // [d3].Derived.Dispose(true) // [d3] Unmanaged memory freed at 000000000034e420 // [d3].Base.Dispose(true) // [d3] Removed from tracking list: 0000000000bb8560 // // Disposal Scenario: #4 // // // Objects remaining to dispose = 2 // Reference Object: d1, 000000000297b065 // Reference Object: d4, 0000000003553390 // // Dequeueing finalizers... // // [d4].Base.Finalize() // [d4].Derived.Dispose(false) // [d4] Unmanaged memory freed at 000000000034e420 // [d4].Base.Dispose(false) // // [d1].Base.Finalize() // [d1].Derived.Dispose(false) // [d1] Unmanaged memory freed at 000000000034e3f0 // [d1].Base.Dispose(false) ----------