Just try effectivec # _ 10

Source: Internet
Author: User

Item 17: implement the standard dispose pattern implements the standard release Mode

 

● It is time to discuss how to writeCodeTo manage the non-memory resources occupied by these classes. A standard mode is to use the methods provided by the. NET Framework to process non-memory resources. Now it's time to cover how to write your own resourcemanagement code when you create types that contain resources other than memory. A standard pattern is used throughout. net Framework for disposing of unmanaged resources.

 

● The top-level base class in the class inheritance relationship should implement the idisposable interface to release resources. This type should also add an destructor as the final passive mechanism. The root base class in the class hierarchy shocould implement the idisposable interface to free resources. this type shoshould also add a finalizer as a defensive mechanic. both methods should use virtual methods to release resources, so that its derived classes can overload this function to release their own resources. The derived class only reloads this function when it needs to release resources, and must remember to call the methods of the base class.

 

● First, if your class uses non-memory resources, you must have an destructor. You cannot expect your customers to always remember to call the dispose method. Otherwise, some resources will be lost when they forget it. This may be because they didn't call the dispose error, but you also have the responsibility. The only method that ensures proper release of non-memory resources is to create an destructor. So, add a destructor!

 

● When GC is running, it will directly remove garbage objects without analysis structure from the memory. Other destructor objects are stored in the memory. When the Garbage Collector runs, it immediately removes from memory any garbage objects that do not have finalizers. all objects that have finalizers remain in memory. these objects are added to an analysis queue. GC starts a new thread to analyze these objects. After the Destructor completes its work, these junk objects can be removed from the memory. Objects that need finalization stay in memory for far longer than objects without a finalizer. That is to say, the object to be destructed is longer than the object to be destructed in the memory. But you have no choice. If you adopt this passive mode, you must write an destructor when your type occupies unmanaged resources. However, you do not need to worry about performance issues. The next step is to make sure that your users are more simple to use and avoid performance loss caused by destructor.

 

● Implementing the idisposable interface is a standard mode to tell the user and the runtime system that your object occupies resources and must be released in a timely manner. The idisposable interface has only one method:

  Public InterfaceIdisposable
{
VoidDispose ();
}

 

● The Implementation of The idisposable. Dispose () method has the responsibility to complete the following tasks: the implementation of your idisposable. Dispose () method is responsible for four tasks ::
1. Release all unmanaged resources. Freeing all unmanaged resources.
2. Release all managed resources (including events not suspended ). Freeing all managed resources (this includes des unhooking events ).
3. Set a status flag to identify that the object has been processed. You need to check the mark and throw an objectdisposed exception before calling an object that has already been processed. Setting a state flag to indicate that the object has been disposed. You need to check this state and throw objectdisposed tions in your public methods, if any get called after disposing of an object.
4. Block the destructor. You need to call GC. suppressfinalize (this) to complete the final work. Suppressing finalization. You call GC. suppressfinalize (this) to accomplish this task.

 

● By implementing the idisposable interface, you have completed two things: the first is to provide a mechanism to release all the hosted resources in a timely manner, you provide the mechanism for clients to release all managed resources that you hold in a timely fashion, and you provide a standard mode for users to release unmanaged resources. You give clients a standard way to release all unmanaged resources. This is very important. When you implement the idisposable interface on your type, you can avoid the loss of structure analysis.

 

● However, some vulnerabilities still exist in the mechanism you created. How can I make a derived class clean up its own resources and let the base class handle it? If the derived classes overload the Destructor or add the implementation of idisposable, these methods must call the basic method. Otherwise, the base class cannot clear resources correctly.

 

● Likewise, the organization and processing share some of the same responsibilities: You can be sure that there are many duplicates in the code between the method and the processing method. As you will learn in principle 26, the method of reloading interfaces does not work as expected. The third method in the standard dispose mode uses a protected auxiliary virtual function to create common tasks and mount them to a derived class to release resources. The base class contains the core code of the interface. The dispose () virtual function or destructor provided by the derived class is responsible for clearing resources:

Protected virtual void dispose (bool isdisposing );

This overload method is required for finalize and dispose, and because it is a virtual function, it provides function entry points for all derived classes. A derived class can overload this function, provide an appropriate implementation to release its own resources, and call the function of the base class. When isdisposing is true, you may clear both managed and unmanaged resources. When isdisposing is false, you can only clear unmanaged resources. In both cases, you can call the dispose (bool) method of the base class to clear its own resources.

 

● Here is a simple example here is a short sample that shows the framework of code you supply when you implement this pattern. the myresourcehog class demonstrates the implementation of idisposable, an destructor, and creates a virtual dispose method:

  Public     Class  Myresourcehog: idisposable
{
// Flag for already disposed released flag
Private Bool Alreadydisposed = False ;
// Implementation of idisposable.
// Call the virtual dispose method.
// Suppress finalization.
Public Void Dispose ()
{
Dispose ( True );
GC. suppressfinalize ( This );
}
// Virtual dispose method
Protected Virtual Void Dispose ( Bool Isdisposing)
{
// Don't dispose more than once.
If (Alreadydisposed)
Return ;
If (Isdisposing)
{
// Elided: Free managed resources here.
}
// Elided: Free unmanaged resources here.
// Set disposed flag:
Alreadydisposed = True ;
}
Public Void Examplemethod ()
{
If (Alreadydisposed)
Throw New Objectdisposedexception (
" Myresourcehog " ,
" Called example Method on disposed object " );
// Remainder elided.
}
}

If the derived class has another cleanup task, let it implement the dispose method:

  Public     Class  Derivedresourcehog: myresourcehog
{
// Have its own disposed flag.
Private Bool Disposed = False ;
Protected Override Void Dispose ( Bool Isdisposing)
{
// Don't dispose more than once.
If (Disposed)
Return ;
If (Isdisposing)
{
// Todo: Free managed resources here.
}
// Todo: Free unmanaged resources here.
// Let the base class free its resources.
// Base class is responsible for calling
// GC. suppressfinalize ()
Base . Dispose (isdisposing );
// Set derived class disposed flag:
Disposed = True ;
}
}

Note that both the derived class and the base class have a processing status mark, which is completely passive. The duplicate mark masks any possible errors during processing and is a single type of processing, rather than processing all types that constitute this object.

 

You should passively write the processing method and the Destructor write dispose and finalize defensively. The processing objects may occur in any order. You may encounter this situation: A member of your class has been processed before you call the dispose method. You didn't see this because the dispose () method can be called multiple times. If you call this method on an object that has been processed, nothing happens. Destructor have the same rules. When any object is referenced in memory, you do not need to detect null references. However, the referenced object may have been processed or parsed.

 

● This introduces a very important piece of advice: For any methods related to processing and resource clearing, you must only release resources! Do not add any other tasks during processing. The object was born when you created it and died when the Garbage Collector claimed it. You can think that when yourProgramThey are sleep when they are no longer accessible. You cannot access the object and call the method of the object. There are signs that they are like dead. However, before an object is declared dead, the Destructor had a final breath. The Destructor should not do anything, that is, clean up unmanaged resources. If the Destructor makes the object accessible in some ways, it will be revived. The Destructor are not called by the user or called by the. NET System, but run on the additional thread generated by the GC. It even wakes up from sleep. Here is an obvious example:

  Public     Class  Badclass
{
// Store a reference to a global object:
Private Static Readonly List < Badclass > Finalizedlist =
New List < Badclass > ();
Private String MSG;
Public Badclass ( String MSG)
{
// Cache the reference:
MSG = ( String ) Msg. Clone ();
}
~ Badclass ()
{
// Add this object to the list.
// This object is reachable, no
// Longer garbage. It's back!
Finalizedlist. Add ( This );
}
}

 

When a badclass object's destructor is executed, it adds its own reference to the global linked list. This makes it reachable, And it will survive again. The method described above will encounter some daunting problems. The object has been destructed, so the Garbage Collector will no longer need to call its destructor. If you want to analyze an reachable object, this will not succeed. Second, some of your resources may no longer be useful. GC no longer removes objects referenced by the Destructor queue from the memory, but they may have been destructed. If so, they are probably no longer usable. That is to say, after the above method is used to restore an object, it is very likely that the object is unavailable .) Although the members of badclass are still in the memory, they may be destructed or processed, but the C # language does not have a way for you to control the order of the destructor, you cannot make such a structure run reliably. Do not try.

 

I have not seen such code: to restore an object in such an obvious way, unless it is an academic exercise. But I have read this Code. The Destructor tries to complete some substantive work, and finally puts the reference into the object through calling the destructor, so as to restore itself. The code in the Destructor looks well-designed, and there are also processing functions. Check again. These codes do other things, instead of releasing resources! These actions will generate many bugs for your application in later stages. Delete these methods to ensure that the Destructor and dispose () methods do nothing except clean up resources.

 

In a hosted environment, you do not need to write destructor for each created class. You can add them only when you need to release some of the used unmanaged resources, or when the members in your class have implemented the idisposable interface, they must also be added. Even so, you only need to implement the idisposable interface to complete all the functions without the need for destructor. Otherwise, you will restrict the implementation of standard dispose in your derived classes. Follow the standard dispose habits I described. This will make your program life easier, and also create a derived class for your users.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.