Free mag vol1 | Page 545

CHAPTER 13  UNDERSTANDING OBJECT LIFETIME  Note It is illegal to override Finalize() on structure types. This makes perfect sense given that structures are value types, which are never allocated on the heap to begin with and, therefore, are not garbage collected! However, if you create a structure that contains unmanaged resources that need to be cleaned up, you can implement the IDisposable interface (described shortly). Of course, a call to Finalize() will (eventually) occur during a “natural” garbage collection or possibly when you programmatically force a collection via GC.Collect(). In addition, a type’s finalizer method will automatically be called when the application domain hosting your application is unloaded from memory. Depending on your background in .NET, you may know that application domains (or simply AppDomains) are used to host an executable assembly and any necessary external code libraries. If you are not familiar with this .NET concept, you will be by the time you’ve finished Chapter 17. For now, note that when your AppDomain is unloaded from memory, the CLR automatically invokes finalizers for every finalizable object created during its lifetime. Now, despite what your developer instincts may tell you, the vast majority of your C# classes will not require any explicit cleanup logic or a custom finalizer. The reason is simple: if your classes are just making use of other managed objects, everything will eventually be garbage-collected. The only time you would need to design a class that can clean up after itself is when you are using unmanaged resources (such as raw OS file handles, raw unmanaged database connections, chunks of unmanaged memory, or other unmanaged resources). Under the .NET platform, unmanaged resources are obtained by directly calling into the API of the operating system using Platform Invocation Services (PInvoke) or as a result of some very elaborate COM interoperability scenarios. Given this, consider the next rule of garbage collection:  Rule The only compelling reason to override Finalize() is if your C# class is making use of unmanaged resources via PInvoke or complex COM interoperability tasks (typically via various members defined by the System.Runtime.InteropServices.Marshal type). The reason is that under these scenarios, you are manipulating memory that the CLR cannot manage. Overriding System.Object.Finalize() In the rare case that you do build a C# class that uses unmanaged resources, you will obviously want to ensure that the underlying memory is released in a predictable manner. Suppose you have created a new C# Console Application named SimpleFinalize and inserted a class named MyResourceWrapper that uses an unmanaged resource (whatever that might be) and you want to override Finalize(). The odd thing about doing so in C# is that you can’t do it using the expected override keyword. class MyResourceWrapper { // Compile-time error! protected override void Finalize(){ } } 486