This article describes the C# resource release method. Share it for your reference, as follows:
1、try{}finally{}
2、using
Only types implement the IDisposable interface and overriding the Dispose() method can use the using statement to achieve resource release.
First, let’s take a look at the explanation of this interface in MSDN:
[ComVisible(true)] public interface IDisposable { // Methods void Dispose(); }
1.[ComVisible(true)]:
Indicates that the managed type is visible to COM.
2. The main purpose of this interface is to release unmanaged resources.
When a managed object is no longer used, the garbage collector automatically frees the memory allocated to that object. But it is impossible to predict the time for garbage collection. Additionally, the garbage collector knows nothing about unmanaged resources such as window handles or open files and streams. Use the Dispose method of this interface with the garbage collector to explicitly release unmanaged resources. When an object is no longer needed, the object's consumer can call this method.
1. Basic Application
1. Let’s define a class that implements the IDisposable interface, the code is as follows:
public class TestClass :IDisposable { public void DoSomething() { ("Do some thing...."); } public void Dispose() { ("Release resources in a timely manner"); } }
2. We have two ways to call:
2.1. The first method is to use the Using statement to automatically call the Dispose method, the code is as follows:
using (TestClass testClass = new TestClass()) { (); }
2.2 The second method is to actually call the Dispose method of this interface, the code is as follows:
TestClass testClass = new TestClass(); try { (); } finally { IDisposable disposable = testClass as IDisposable; if (disposable != null) (); }
The execution results of the two methods are the same.
2.3. The advantage of using try/catch/finally is that after catching exceptions, they can be processed and at the same time they can also release resources; however, using using, resources can be released even if there are exceptions, but the exception cannot be processed, and the exception is released directly. In fact, these two methods are the same in the release of resources.
2. Disposable mode
1. In .NET, since the Finalize method will be automatically called when the object becomes inaccessible, the Dispose method of the IDisposable interface is extremely similar to the method called by the object terminal. We'd better put them together to handle it.
The first thing that comes to mind is to rewrite the Finalize method, as follows:
protected override void Finalize() { ("Destructor execution..."); }
When we compile this code, we find that the compiler will report the following error: This is because the compiler completely blocks the Finalize method of the parent class. The compiler prompts us that if we want to rewrite the Finalize method, we need to provide a destructor instead. Let us provide a destructor:
~TestClass() { ("destructor execution..."); }
In fact, this destructor compiler will convert it into the following code:
protected override void Finalize() { try { ("Destructor execution..."); } finally { (); } }
2. Then we can put the call of the Dispose method and the object's finalizer together to process it, as follows:
public class TestClass: IDisposable { ~TestClass() { Dispose(); } public void Dispose() { // Clean up resources } }
3. The above implementation actually calls the Dispose method and Finalize method, which may lead to repeated cleaning work, so the following classic Disposable mode is available:
private bool _isDisposed = false; public void Dispose() { Dispose(true); (this); } protected void Dispose(bool Diposing) { if(!_isDisposed) { if(Disposing) { //Clean hosting resources } //Clean unmanaged resources } _isDisposed=true; } ~TestClass() { Dispose(false); }
3.1. SupressFinalize method to prevent the garbage collector from calling () on objects that do not require termination.
3.2. Usage method, users can free resources at any time before objects can be collected as garbage. If a method is called, this method releases the object's resources. In this way, there is no need to terminate. It should be called so that the garbage collector does not call the object's finalizer.
3.3. We do not want the Dispose(bool Dipose) method to be called externally, so its access level is protected. If Dipose is true, the managed and unmanaged resources are released, and if Dipose is equal to false, the method has been called from inside the terminal by the runner and can only free unmanaged resources.
3.4. If other methods are called after the object is released, an ObjectDisposedException may be raised.
III. Example analysis
1. The following code encapsulates the Dispose method, explaining a general example of how to implement Dispose(bool) in a class that uses managed and native resources:
public class BaseResource : IDisposable { // Unmanaged resources private IntPtr _handle; //Host resources private Component _components; // Is Dispose called? private bool _disposed = false; public BaseResource() { } public void Dispose() { Dispose(true); (this); } protected virtual void Dispose(bool disposing) { if (!this._disposed) { if (disposing) { // Release managed resources _components.Dispose(); } // Release unmanaged resources. If disposing is false, only unmanaged resources are released CloseHandle(_handle); _handle = ; // Note that this is not thread-safe } _disposed = true; } // The destructor will only be called when we do not call the Dispose method directly // Derived classes do not need to provide destructors in the second ~BaseResource() { Dispose(false); } // If you have called the Dispose method and then called other methods, an ObjectDisposedException will be thrown public void DoSomething() { if (this._disposed) { throw new ObjectDisposedException(); } } } public class MyResourceWrapper : BaseResource { // Hosted resources private ManagedResource _addedManaged; // Unmanaged resources private NativeResource _addedNative; private bool _disposed = false; public MyResourceWrapper() { } protected override void Dispose(bool disposing) { if (!this._disposed) { try { if (disposing) { _addedManaged.Dispose(); } CloseHandle(_addedNative); this._disposed = true; } finally { (disposing); } } } }
2. With the CLR garbage collector, you no longer have to worry about how to manage the memory allocated to the managed heap, but you still need to clean up other types of resources. Managed classes allow their users to release potentially important resources before the garbage collector terminates the object. By following the disposable pattern and paying attention to issues that need to be paid attention to, a class ensures that all its resources are cleaned correctly and that no problems occur when cleaning code is run directly through Dispose calls or through the finalizer thread.
I hope this article will be helpful to everyone's C# programming.