|
|
[ Pobierz całość w formacie PDF ]
Finalize method, the Dispose method is public. It can be called directly by a user of the class, as opposed to relying on the garbage collector to call it. This gives you back control of freeing resources, but calling Dispose still does not reclaim memory for the object itself - that is still for the garbage collector to do. Note that some classes in the .NET Framework implement both Dispose, and another method such as Close. Typically the Close method simply calls Dispose, but the extra method is provided because it seems more "natural" for certain classes such as files. Delphi for .NET classes are free to use the Finalize method for freeing system resources, however the recommended method is to implement the dispose pattern. The Delphi for .NET compiler recognizes a very specific destructor pattern in your class, and implements the IDisposable interface for you. This enables you to continue writing new code for the .NET platform the same way you always have, while allowing much of your existing Win32 Delphi code to run in the garbage collected environment of the CLR. The compiler recognizes the following specific pattern of a Delphi destructor: TMyClass = class(TObject) destructor Destroy; override; end; Your destructor must fit this pattern exactly: The name of the destructor must be Destroy. The keyword override must be specified. The destructor cannot take any parameters. In the compiler's implementation of the dispose pattern, the Free method is written so that if the class implements the IDisposable interface (which it does), then the Dispose method is called, which in turn calls your destructor. You can still implement the IDisposable interface directly, if you choose. However, the compiler's automatic implementation of the Free-Dispose-Destroy mechanism cannot coexist with your implementation of IDisposable. The two methods of implementing IDisposable are mutually exclusive. You must choose to either implement IDisposable directly, or equip your class with the familiar destructor Destroy; override pattern and rely on the compiler to do the rest. The Free method will call Dispose in either case, but if you implement Dispose yourself, you must call your destructor yourself. If you want to implement IDisposable yourself, your destructor cannot be called Destroy. Note: You can declare destructors with other names; the compiler only provides the IDisposable implementation when the destructor fits the above pattern. The Dispose method is not called automatically; the Free method must be called in order for Dispose to be called. If an object is freed by the garbage collector because there are no references to it, but you did not explicitly call Free on the object, the object will be freed, but the destructor will not execute. Note: When the garbage collector frees the memory used by an object, it also reclaims the memory used by all fields of the object instance as well. This means the most common reason for implementing destructors in Delphi for Win32 - to release allocated memory - no longer applies. However, in most cases, unmanaged resources such as window handles or file handles still need to be released. To eliminate the possibility of destructors being called more than once, the Delphi for .NET compiler introduces a field called DisposeCount into every class declaration. If the class already has a field by this name, the name collision will cause the compiler to produce a syntax error in the destructor. 217 Unit Initialization and Finalization On the .NET platform, units that you depend on will be initialized prior to initializing your own unit. However, there is no way to guarantee the order in which units are initialized. Nor is there a way to guarantee when they will be initialized. Be aware of initialization code that depends on another unit's initialization side effects, such as the creation of a file. Such a dependency cannot be made to work reliably on the .NET platform. Unit finalization is subject to the same constraints and difficulties as the Finalize method of objects. Specifically, unit finalization is asynchronous, and, there no way to determine when it will happen (or if it will happen, though under most circumstances, it will). Typical tasks performed in a unit finalization include freeing global objects, unregistering objects that are used by other units, and freeing resources. Because .NET is a memory managed environment, the garbage collector will free global objects even if the unit finalization section is not called. The units in an application domain are loaded and unloaded together, so you do not need to worry about unregistering objects. All units that can possibly refer to each other (even in different assemblies) are released at the same time. Since object references do not cross application domains, there is no danger of something keeping a dangling reference to an object type or code that has been unloaded from memory. Freeing resources (such as file handles or window handles) is the most important consideration in unit finalization. Because unit finalization sections are not guaranteed to be called, you may want to rewrite your code to handle this issue using finalizers rather than relying on the unit finalization. The main points to keep in mind for unit initialization and finalization on the .NET platform are: 1 The Finalize method is called asynchronously (both for objects, and for units). 2 Finalization and destructors are used to free unmanaged resources such as file handles. You do not need to destroy object member variables; the garbage collector takes care of this for you. 3 Classes should rely on the compiler's implementation of IDisposable, and provide a destructor called Destroy. 4 If a class implements IDisposable itself, it cannot have a destructor called Destroy. 5 Reference counting is deprecated. Try to use the destructor Destroy; override; pattern wherever possible. 6 Unit initialization should not depend on side effects produced by initialization of dependent units. Unit Initialization Considerations for Assemblies and Dynamically Linked Packages Under Win32, the Delphi compiler uses the DllMain function as a hook from which to execute unit initialization code. No such execution path exists in the .NET environment. Fortunately, other means of implementing unit initialization exist in the .NET Framework. However, the differences in the implementation between Win32 and .NET could impact the order of unit initialization in your application. The Delphi for .NET compiler uses CLS-compliant class constructors to implement unit initialization hooks. The CLR requires that every object type have a class constructor. These constructors, or type initializers, are guaranteed to be executed at most one time. Class constructors are executed at most one time, because in order for the type to be loaded, it must be used. That is, the assembly containing a type will not be loaded until the type is actually used at runtime. If the assembly is never loaded, its unit initialization section will never run. Circular unit references also impact the unit initialization process. If unit A uses unit B, and unit B then uses unit A in its implementation section, the order of unit initialization is undefined. To fully understand the possibilities, it is helpful to look at the process one step at a time. 1 Unit A's initialization section uses a type from unit B. If this is the first reference to the type, the CLR will load its assembly, triggering the unit initialization of unit B. 2 As a consequence, loading and initializing unit B occurs before unit A's initialization section has completed execution. Note this is a change from how unit initialization works under Win32. 218
[ Pobierz całość w formacie PDF ] zanotowane.pldoc.pisz.plpdf.pisz.plkwiatpolny.htw.pl
|
|
Cytat |
Dobre pomysły nie mają przeszłości, mają tylko przyszłość. Robert Mallet De minimis - o najmniejszych rzeczach. Dobroć jest ważniejsza niż mądrość, a uznanie tej prawdy to pierwszy krok do mądrości. Theodore Isaac Rubin Dobro to tylko to, co szlachetne, zło to tylko to, co haniebne. Dla człowieka nie tylko świat otaczający jest zagadką; jest on nią sam dla siebie. I z obu tajemnic bardziej dręczącą wydaje się ta druga. Antoni Kępiński (1918-1972)
|
|