On aliasing the Dispose name…


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> href="mailto:michael%20dot%20bouckAT%20NOSPAMpeoplefirst%20dot%20com">Michael
href="http://blogs.gotdotnet.com/BradA/commentview.aspx/d7cdc5f8-4b4b-4b00-a5b2-c9fad3621e2d">argues
that the guideline we have around using a customized name for the Dispose method
is a bad idea because it adds developer confusion. style="mso-spacerun: yes">   This is a reasonable argument, and
one that heavy hitters such as
"urn:schemas-microsoft-com:office:smarttags" /> prefix = st1 ns = "urn:schemas:contacts" /> size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Jeffrey face=Arial size=2>
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Richter
face=Arial size=2> buy into as
well, so it is worth some careful thought. "urn:schemas-microsoft-com:office:office" />


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">I think the easiest way to
understand this issue is via an example, let’s take a look at the href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemIOFileStreamClassTopic.asp">System.IO.FileStream
class… currently it is defined as:


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial">public
class FileStream: Stream, IDisposable {


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">    //all the normal
methods


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">   void IDisposable.Dispose () {
//explicitly implemented


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">       //close
the file handle, etc


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">   }


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">  public void Close ()
{


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">    
Dispose();


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-spacerun: yes">  }


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial">}


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Notice that the Dispose method is
not public… it is href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkExplicitInterfaceImplementationTutorial.asp">explicitly
implemented on the class.  This
means that the Dispose method can only be called directly when an instance of
the FileStream class is cast to IDisposable. style="mso-spacerun: yes">  We also provide Close() method that is
publicly accessible off the FileStream class.


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-tab-count: 1">      FileStream s =
new FileStream (…);


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-tab-count: 1">      s.Close();//
works great


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-tab-count: 1">      s.Dispose();
//compile error


size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-font-family: Arial"> style="mso-tab-count: 1">      ((IDisposable)
s).Dispose(); //works great


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">We use this combination in order
to:


style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1; tab-stops: list .75in"> face=Arial size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: Arial; mso-fareast-font-family: Arial"> style="mso-list: Ignore">1. style="FONT: 7pt 'Times New Roman'">      
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Meet the time honored expectation
that file related things are “Closed” not “Disposed”, etc. style="mso-spacerun: yes">  We did not want to force every developer
to learn the Dispose is just “our name for Close”…


style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1; tab-stops: list .75in"> face=Arial size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: Arial; mso-fareast-font-family: Arial"> style="mso-list: Ignore">2. style="FONT: 7pt 'Times New Roman'">      
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">We wanted to enable FileStream to
plug into generic mechanisms for ensure deterministic finalization such as C#’s
using statement. 


style="MARGIN: 0in 0in 0pt 0.75in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1; tab-stops: list .75in"> face=Arial size=2> style="FONT-SIZE: 10pt; FONT-FAMILY: Arial; mso-fareast-font-family: Arial"> style="mso-list: Ignore">3. style="FONT: 7pt 'Times New Roman'">      
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">We wanted only one way to
Close\Dispose a file in explicitly in code. style="mso-spacerun: yes">  


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">The
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Jeff face=Arial size=2> and
style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">Michael face=Arial size=2> camp would
rather see us have only the Dispose method (if my understanding is right). style="mso-spacerun: yes"> 
While that meets goals 2 and 3 outlined
above, I believe the fact that it fails 1 is a significant enough problem to
warrant the additional implementation complexity of our current story. style="mso-spacerun: yes">  I say implementation complexity because
I don’t believe that many users actually find any additional complexity with
this design.  They just use Close()
and\or C#’s using support and have no problems.


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial">That said, I have sympathy for the
argument and, like most features explicit implementation can be abused. style="mso-spacerun: yes">  As such we are working on a guideline
right now to help clear that up. 
Suggestions always welcome!


style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"> 

Comments (16)

  1. JosephCooney says:

    re: Close vs. Dispose…what about the SqlConnection class? It implements Close() and Dispose(). From looking at the dis-assembly it looks like Dispose() calls Close() but not the other way around (but that could just be me). I understand this may have been done for connection pooling reasons, but is still makes things somewhat confusing.

  2. Michael Bouck says:

    Didn’t know I was in the Jeff Richter camp! :-) I’m OK with this argument except for the fact that goal 1 is relying completely on the developer to "do the right thing" (i.e. implementing Dispose() explicitly and privately). I don’t know about you, but I have seen best practices thrown out the window too many times to count (that’s why smart pointers were so cool, right? It automatically saved the guy who didn’t remember to AddRef()/Release() his interfaces (in most cases)). I’ve already seen violations of this rule in third party code and boy is it ugly when I see Dispose(), Close(), Release(), Free(), etc. all defined as public! Mostly though, and I might be being a bit pedantic, it’s the "purity thing" (goal 3) that appeals to me. To be able to say, categorically, that DF is accomplished, always, in one way makes life easier on everyone. Sure, the VB guy is going to be a bit confused at first but I would argue he’s going to be much more confused getting used to OOP in the first place. It’s more orthogonal to see a random class in the object viewer which implements IDisposable and know that there is exactally one way to get rid of it.

    Having said that, if the majority still thinks this is the right way to go, I’d like to propose that the compiler at least emit a warning if Dispose() is aliased by a public method and is not explicitly implemeneted privately. FxCop isn’t sufficient in my opinion, because the guy that is abusing goal 1 probably isn’t running FxCop either…

  3. Matthew Adams says:

    By an extraordinary coincidence, I was having this converstaion on Friday. Personally, I think that Dispose() is a big problem in the developer community at large. Whiilst it does provide a form of deterministic finalization, people associate the term ‘finalize’ with ‘garbage collect’, which Dispose() most certainly does not.

    Implementing Dispose() as an under the covers method to support the ‘using’ idiom is fine, but, otherwise, you should really provide an explicitly documented life-cycle management policy for your object, and a separate idiom is best for that (and hence *at least* a separate method). Personally, I prefer an Acquire/Release approach from an entirely separate manager for the limited resource, and Ian suggested a duration-of-work approach, rather like DataAdapter.Fill().

    Whichever way you cut it, Dispose() is essential, when it is absolutely essential, but it is over-used and badly understood at the moment. And that makes it a dangerous tool.

  4. Re: The earlier comment about Close vs. Dispose in SqlConnection…
    In SqlConnection, Close and Dispose are not the same thing. As expected, Dispose completely releases resources, and the instance can’t be used for anything ever again, try it and you’ll get an ObjectDisposed exception. On the other hand, SqlConnection.Close is similar, but enables you to reuse the same instance later. Dispose depends on Close to cleanup.

  5. Actually, I’m not opposed to FileStream offerring Close. What I am opposed to is "hiding" Dispose and forcing the FileStream variable to be cast to IDisposable in order to call Dispose. I’d be OK if both Close and Dispose were _equally_ callable.

  6. Frank Hileman says:

    I agree mostly with Jeffrey. Hiding Dispose just introduces unnecessary inconsistencies. But if people have to learn to use the .net framework, they will have to learn about Dispose, and as soon as they have learned, redundant functions such as Close just add confusion.

  7. Kevin Wan says:

    当我们开发C#代码的时候,经常碰到一个问题,有些class提供Close(),有些class提供Dispose(),而且有些class里面还提供了Dispose(bool),那么Dispose和Close到底有什么区别?

  8. 夏亚兵 says:

    当我们开发C#代码的时候,经常碰到一个问题,有些class提供Close(),有些class提供Dispose(),那么Dispose和Close到底有什么区别?首先,Dispose和Close基本上…

  9. 勤勤同学 says:

    当我们开发C#代码的时候,经常碰到一个问题,有些class提供Close(),有些class提供Dispose(),那么Dispose和Close到底有什么区别?

  10. 原文地址:http://www.cnblogs.com/kevinwan/archive/2007/01/16/621869.html 当我们开发C#代码的时候,经常碰到一个问题,有些clas…

  11. ljsql says:

    正确实现IDisposable Dispose和Close的区别

  12. 原文地址:http://www.cnblogs.com/kevinwan/archive/2007/01/16/621869.html 当我们开发C#代码的时候,经常碰到一个问题,有些clas…