C # correct implementation of the idisposable Interface

Source: Internet
Author: User

In. net, the interface used to release object Resources is idisposable, but the implementation of this interface is still very exquisite. In addition, there are two functions: Finalize and close.

 

Public class FOO: idisposable
{
Public void dispose ()
{
Dispose (true );
GC. suppressfinalize (this );
}
 
Protected virtual void dispose (bool disposing)
{
If (! M_disposed)
{
If (disposing)
{
// Release managed resources
}

// Release unmanaged Resources

M_disposed = true;
}
}

~ Foo ()
{
Dispose (false );
}

Private bool m_disposed;
}

In fact, there are two functions used to release resources in the. NET object: dispose and finalize. Finalize is used to release unmanaged resources, while dispose is used to release all resources, including hosted and unmanaged resources.

 

In this mode, the void dispose (bool disposing) function uses a disposing parameter to determine whether the current call is called by dispose. If it is called by dispose (), you need to release both hosted and unmanaged resources. If it is ~ Foo () (that is, the finalize () of C #) is called, you only need to release the unmanaged resources.

 

This is because the dispose () function is explicitly called by other code and requires resource release, while finalize is called by GC. Other Managed Objects referenced by foo during GC calls may not need to be destroyed, and GC calls the objects even if they are to be destroyed. Therefore, you only need to release unmanaged resources in finalize. On the other hand, because managed and unmanaged resources have been released in dispose (), it is unnecessary to call finalize again when the object is recycled by GC. Therefore, in dispose (). suppressfinalize (this) prevents repeated calls to finalize.

 

However, even if you call finalize and dispose repeatedly, the resource is released only once because of the existence of the variable m_disposed. Excessive calls are ignored.

 

Therefore, the above mode ensures that:

 

1. Finalize only releases unmanaged resources;

2. Dispose releases managed and unmanaged resources;

3. It is no problem to repeatedly call finalize and dispose;

4. Finalize and dispose share the same resource release policy, so there is no conflict between them.

 

In C #, this mode needs to be implemented explicitly, where C #'s ~ The Foo () function represents finalize (). In C ++/CLI, this mode is automatically implemented, and the class destructor of C ++ are different.

 

According to the C ++ semantics, The Destructor is called when it is out of scope or delete. In managed C ++ (I .e. in the managed C ++ in net 1.1, destructor are equivalent to the finalize () method in Clr and called by GC during garbage collection. Therefore, the call time is not clear. In C ++/CLI of. NET 2.0, the semantics of the Destructor is modified to the equivalent and dispose () methods, which implies two things:

 

1. All the CLR classes in C ++/CLI implement the interface idisposable. Therefore, you can use the using keyword in C # To access the instances of this class.

2. destructor are no longer equivalent to finalize.

 

This is a good thing for the first point. I think in terms of semantics, dispose () is closer to C ++ destructor. For the second point, Microsoft made an extension by introducing "!". Function:

1 Public ref class foo
2 {
3 public:
4 Foo ();
5 ~ Foo (); // destructor
6! Foo (); // finalizer
7 };
8
 

"!" Function (I really don't know how to call it) is called by GC instead of finalize () in the original managed C ++. Msdn recommends that you write the following code to reduce code duplication:

1 ~ Foo ()
2 {
3 // release managed resources
4 This->! Foo ();
5}
6
7! Foo ()
8 {
9 // release unmanaged Resources
10}
11
 

For the above class, C ++/CLI generates the corresponding C # Code as follows:

 

1 public class foo
2 {
3 private void! Foo ()
4 {
5 // release unmanaged Resources
6}
7
8 private void ~ Foo ()
9 {
10 // release managed resources
11! Foo ();
12}
13
14 public Foo ()
15 {
16}
17
18 public void dispose ()
19 {
20 dispose (true );
21 GC. suppressfinalize (this );
22}
23
24 protected virtual void dispose (bool disposing)
25 {
26 if (disposing)
27 {
28 ~ Foo ();
29}
30 else
31 {
32 try
33 {
34! Foo ();
35}
36 finally
37 {
38 base. Finalize ();
39}
40}
41}
42
43 protected void finalize ()
44 {
45 dispose (false );
46}
47}
48
 

Because ~ Foo () and! Foo () is not repeatedly called (at least Ms thinks so). Therefore, there is no variable identical to m_disposed in this Code, but the basic structure is the same.

 

In addition, we can see that it is not actually ~ Foo () and! Foo () is dispose and finalize, but the C ++/CLI compiler generates two dispose and finalize functions and calls them when appropriate. C ++/CLI has actually done a lot of work, but the only problem is that it depends on the user in ~ Call in Foo! Foo ().

 

The last thing to mention about resource release is the close function. In terms of semantics, it is similar to dispose. According to msdn, this function is provided to make users feel more comfortable, because for some objects, such as files, you are more comfortable calling close ().

 

However, after all, these two functions do the same thing, so the code recommended by msdn is:

 

1 Public void close ()
2 {
3 dispose (();
4}
5
6
Call the dispose function without parameters to obtain the same semantics as dispose. This seems to be complete, but on the other hand, if both dispose and close are provided, it will bring some confusion to the user. Without looking at the code details, it is difficult to know the differences between the two functions. Therefore, in the code design specification of. net, the two functions can only be used by users. Therefore, the recommended mode is:

1 public class FOO: idisposable
2 {
3 Public void close ()
4 {
5 dispose ();
6}
7
8 void idisposable. Dispose ()
9 {
10 dispose (true );
11 GC. suppressfinalize (this );
12}
13
14 protected virtual void dispose (bool disposing)
15 {
16 // same as before
17}
18}
19
 

An explicit implementation of void idisposable. Dispose () is used here (). This explicit implementation can only be accessed through interfaces, but cannot be accessed through implementation classes. Therefore:

 

1 Foo = new Foo ();
2
3 Foo. Dispose (); // Error
4 (FOO as idisposable). Dispose (); // correct
5
 

In this way, both the two are taken into account. For people who like to use close, they can directly use Foo. Close (), and they cannot see dispose (). If you like dispose, you can convert the type to idisposable or use the using statement. Both are happy!

Related Article

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.