![]() | |
![]() |
| | Thread Tools | Search this Thread | Display Modes |
#1
| |||
| |||
|
#2
| |||
| |||
|
|
"There is no gain in performance, maintainability or otherwise by implementing the Dispose method if unmanaged resources are not involved." |
#3
| |||
| |||
|
|
"Cordell Lawrence (News Group)" wrote: "There is no gain in performance, maintainability or otherwise by implementing the Dispose method if unmanaged resources are not involved." There are plenty of uses for IDispose that don't involve unmanaged resources: * Saving and restoring the cursor, in a GUI app. * Saving and restoring thread priority. * Benchmarking code fragments. * Emitting close tags (or matching braces, or whatever). * Automatically calling ResumeLayout and the like. Basically, any time a 'begin' action must be paired with an 'end' action, a `using` statement makes for smaller, less cluttered code ... and guarantees that you won't forget the end action. |
#4
| |||
| |||
|
|
* Saving and restoring the cursor, in a GUI app. * Saving and restoring thread priority. * Benchmarking code fragments. * Emitting close tags (or matching braces, or whatever). * Automatically calling ResumeLayout and the like. Basically, any time a 'begin' action must be paired with an 'end' action, a `using` statement makes for smaller, less cluttered code ... and guarantees that you won't forget the end action. I don't know - I think all of those somewhat abuse the documented purpose of IDisposable. I can see that it's a convenient way of getting try/finally behaviour, but none of the above really feels like an action which would normally be called Dispose, or which fits in with any of the documentation around IDisposable. Put it this way: I might use it for convenience within an internal set of classes, but if I were writing a library I wouldn't implement IDisposable on something that wasn't in *some* way freeing a resource. |
#5
| |||||
| |||||
|
|
Put it this way: I might use it for convenience within an internal set of classes, but if I were writing a library I wouldn't implement IDisposable on something that wasn't in *some* way freeing a resource. I do see your point, but I'm not really sure how valid it is, at least in the context of C# and the `using` statement, where you don't actually see a Dispose() call. (Languages like Delphi for .NET that lack a `using` statement are a different story.) |
|
The way I see it, implementing IDispose in these cases just means that you can use a `using` statement to make your code smaller and less cluttered. I admit there is a certain amount of semantic violence, but there are three reasons I don't think that matters, here. A) Semantic violence matters where there's a possibility of confusion, which I don't think is the case, here. I would, in fact, argue that the smaller code is clearer. |
|
B) There's already a certain amount of fuzziness around the IDispose pattern. with things like streams exporting Close methods instead of Dispose methods. |
|
C) Some of the other system patterns are used pretty loosely, like IEnumerable, with its special casing for arrays, classes that implement GetEnumerator but not IEnumerable, and iterators that don't implement Reset, &c. |
|
Besides, I think I can argue with a straight face that the tiny little IDisposable class that one creates for all the examples above constitute a sort of managed resource that needs to be freed - that you are creating a resource that frees you from the need to explicitly code your 'end' action. |

#6
| |||
| |||
|
|
Jon Shemitz <jon (AT) midnightbeach (DOT) com> wrote: Put it this way: I might use it for convenience within an internal set of classes, but if I were writing a library I wouldn't implement IDisposable on something that wasn't in *some* way freeing a resource. I do see your point, but I'm not really sure how valid it is, at least in the context of C# and the `using` statement, where you don't actually see a Dispose() call. (Languages like Delphi for .NET that lack a `using` statement are a different story.) If I write a library, it doesn't matter whether I write it in C# or not - it could be used in a different language (eg Delphi.NET) which *doesn't* have a using statement. The way I see it, implementing IDispose in these cases just means that you can use a `using` statement to make your code smaller and less cluttered. I admit there is a certain amount of semantic violence, but there are three reasons I don't think that matters, here. A) Semantic violence matters where there's a possibility of confusion, which I don't think is the case, here. I would, in fact, argue that the smaller code is clearer. Where it's present - but if you end up calling Dispose() explicitly from other languages, surely that would cause confusion. That's why I made my comment about the difference between using it effectively for private use and exposing it as part of a public class. B) There's already a certain amount of fuzziness around the IDispose pattern. with things like streams exporting Close methods instead of Dispose methods. Not usually "instead of" - "as well as". Close() is there for the sake of familiarity with previous APIs, IMO. C) Some of the other system patterns are used pretty loosely, like IEnumerable, with its special casing for arrays, classes that implement GetEnumerator but not IEnumerable, and iterators that don't implement Reset, &c. That's certainly true. Besides, I think I can argue with a straight face that the tiny little IDisposable class that one creates for all the examples above constitute a sort of managed resource that needs to be freed - that you are creating a resource that frees you from the need to explicitly code your 'end' action. You're clearly better able to maintain a straight face than I am ![]() -- Jon Skeet - <skeet (AT) pobox (DOT) com http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
#7
| |||
| |||
|
|
Hi Cordell, To address #3: The C# using statement doesn't guarantee anything except that it will compile to a try..finally block and call Dispose. The CLR doesn't guarantee execution of the finally block unless it's part of a CER, so saying that the C# using statement can be used to "guarantee" that the Dispose method is called isn't entirely accurate. It serves only aesthetical purposes since a try..finally block could easily be coded in its place, providing no guarantees as well. Regardless, I like that TransactionScope allows for use of the C# using statement - it looks much nicer and reads better, IMO. Though, semantically, it's wrong if you consider that it's actually calling Dispose(), which is meant to free unmanaged resources. It's a shame there isn't a different mechanism for calling a method in place of Dispose, such as a "with" block that calls a "Complete" method on an "IScopedOperation" interface - or something. Actually, that might be a bad idea ![]() -- Dave Sexton "Cordell Lawrence (News Group)" <cordell_lawrence (AT) hotmail (DOT) com> wrote in message news:OWVfQ%23bEHHA.3820 (AT) TK2MSFTNGP02 (DOT) phx.gbl... Guys, thank you for all the valuable input. Let me now add my two cents: The official (and much bloged) documented purpose of IDisposable revolves around the management of memory (unmanaged and disposable managed instances) and advice on the proper use of the pattern and Finalizers. Facts: 1. IDisposable.Dispose() is just a normal method, it has no special meaning to the runtime 2. IDisposable.Dispose() must be called explicitly by the developer 3. The .NET 'using' syntax is a little more than a syntactic sugar - It guarantees that the Dispose() method is called at the end of the using scope -*And! When using this construct the compiler ensures that the 'using variables' cannot be modified either directly or indirectly through passing it as out or ref parameters to other method anywhere within the using scope To me, these are all points for this pattern being used for more that memory clean up, and this is evidenced by the implementation of for example System.Transactions.TransactionScope. Most of the Dispose() method of the TransactionScope type deals with maintaining State (on the ThreadStatic variables that maintain info about the current Transaction etc.) Check out the following link where Stephen Toub uses the properties of this pattern to implement his Scope<T> type. http://msdn.microsoft.com/msdnmag/is...s/default.aspx I find it interesting that designers of both types chose the following: using ( Scope<object> scope = new Scope<object>() ) { // code that is sensitive to the scope } As opposed to: Scope<object> scope = new Scope<object>(); scope.Begin(); // code that is sensitive to the scope scope.End(); I mean beyond the syntactic brevity, it seems like it was a conscious choice to use the dispose pattern in this way. I mean you could argue that Transactions and the generic T in the scope may implement IDisposable and so, in keeping with good design the designers decided use the dispose pattern and will recursively call Dispose() on its disposable members, but I find that hard to swallow. As for the semantic confusion, I believe that this exists not because of the Naming of the method and interface but its documentation and the context in which this pattern is usually referred to. Cordell Lawrence Teleios Systems Ltd. "Jon Skeet [C# MVP]" <skeet (AT) pobox (DOT) com> wrote in message news:MPG.1fd4289d383bb87898d667 (AT) msnews (DOT) microsoft.com... Jon Shemitz <jon (AT) midnightbeach (DOT) com> wrote: Put it this way: I might use it for convenience within an internal set of classes, but if I were writing a library I wouldn't implement IDisposable on something that wasn't in *some* way freeing a resource. I do see your point, but I'm not really sure how valid it is, at least in the context of C# and the `using` statement, where you don't actually see a Dispose() call. (Languages like Delphi for .NET that lack a `using` statement are a different story.) If I write a library, it doesn't matter whether I write it in C# or not - it could be used in a different language (eg Delphi.NET) which *doesn't* have a using statement. The way I see it, implementing IDispose in these cases just means that you can use a `using` statement to make your code smaller and less cluttered. I admit there is a certain amount of semantic violence, but there are three reasons I don't think that matters, here. A) Semantic violence matters where there's a possibility of confusion, which I don't think is the case, here. I would, in fact, argue that the smaller code is clearer. Where it's present - but if you end up calling Dispose() explicitly from other languages, surely that would cause confusion. That's why I made my comment about the difference between using it effectively for private use and exposing it as part of a public class. B) There's already a certain amount of fuzziness around the IDispose pattern. with things like streams exporting Close methods instead of Dispose methods. Not usually "instead of" - "as well as". Close() is there for the sake of familiarity with previous APIs, IMO. C) Some of the other system patterns are used pretty loosely, like IEnumerable, with its special casing for arrays, classes that implement GetEnumerator but not IEnumerable, and iterators that don't implement Reset, &c. That's certainly true. Besides, I think I can argue with a straight face that the tiny little IDisposable class that one creates for all the examples above constitute a sort of managed resource that needs to be freed - that you are creating a resource that frees you from the need to explicitly code your 'end' action. You're clearly better able to maintain a straight face than I am ![]() -- Jon Skeet - <skeet (AT) pobox (DOT) com http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
#8
| |||||
| |||||
|
|
The C# using statement doesn't guarantee anything except that it will compile to a try..finally block and call Dispose. The CLR doesn't guarantee execution of the finally block unless it's part of a CER, so saying that the C# using statement can be used to "guarantee" that the Dispose method is called isn't entirely accurate. |

|
It serves only aesthetical purposes since a try..finally block could easily be coded in its place, providing no guarantees as well. |
|
Regardless, I like that TransactionScope allows for use of the C# using statement - it looks much nicer and reads better, IMO. |
, but that IMO, is really a|
Though, semantically, it's wrong if you consider that it's actually calling Dispose(), which is meant to free unmanaged resources. It's a shame there isn't a different mechanism for calling a method in place of Dispose, such as a "with" block that calls a "Complete" method on an "IScopedOperation" interface - or something. Actually, that might be a bad idea ![]() |
But why not use Harry to cook as well?|
Hi Cordell, To address #3: The C# using statement doesn't guarantee anything except that it will compile to a try..finally block and call Dispose. The CLR doesn't guarantee execution of the finally block unless it's part of a CER, so saying that the C# using statement can be used to "guarantee" that the Dispose method is called isn't entirely accurate. It serves only aesthetical purposes since a try..finally block could easily be coded in its place, providing no guarantees as well. Regardless, I like that TransactionScope allows for use of the C# using statement - it looks much nicer and reads better, IMO. Though, semantically, it's wrong if you consider that it's actually calling Dispose(), which is meant to free unmanaged resources. It's a shame there isn't a different mechanism for calling a method in place of Dispose, such as a "with" block that calls a "Complete" method on an "IScopedOperation" interface - or something. Actually, that might be a bad idea ![]() -- Dave Sexton "Cordell Lawrence (News Group)" <cordell_lawrence (AT) hotmail (DOT) com> wrote in message news:OWVfQ%23bEHHA.3820 (AT) TK2MSFTNGP02 (DOT) phx.gbl... Guys, thank you for all the valuable input. Let me now add my two cents: The official (and much bloged) documented purpose of IDisposable revolves around the management of memory (unmanaged and disposable managed instances) and advice on the proper use of the pattern and Finalizers. Facts: 1. IDisposable.Dispose() is just a normal method, it has no special meaning to the runtime 2. IDisposable.Dispose() must be called explicitly by the developer 3. The .NET 'using' syntax is a little more than a syntactic sugar - It guarantees that the Dispose() method is called at the end of the using scope -*And! When using this construct the compiler ensures that the 'using variables' cannot be modified either directly or indirectly through passing it as out or ref parameters to other method anywhere within the using scope To me, these are all points for this pattern being used for more that memory clean up, and this is evidenced by the implementation of for example System.Transactions.TransactionScope. Most of the Dispose() method of the TransactionScope type deals with maintaining State (on the ThreadStatic variables that maintain info about the current Transaction etc.) Check out the following link where Stephen Toub uses the properties of this pattern to implement his Scope<T> type. http://msdn.microsoft.com/msdnmag/is...s/default.aspx I find it interesting that designers of both types chose the following: using ( Scope<object> scope = new Scope<object>() ) { // code that is sensitive to the scope } As opposed to: Scope<object> scope = new Scope<object>(); scope.Begin(); // code that is sensitive to the scope scope.End(); I mean beyond the syntactic brevity, it seems like it was a conscious choice to use the dispose pattern in this way. I mean you could argue that Transactions and the generic T in the scope may implement IDisposable and so, in keeping with good design the designers decided use the dispose pattern and will recursively call Dispose() on its disposable members, but I find that hard to swallow. As for the semantic confusion, I believe that this exists not because of the Naming of the method and interface but its documentation and the context in which this pattern is usually referred to. Cordell Lawrence Teleios Systems Ltd. "Jon Skeet [C# MVP]" <skeet (AT) pobox (DOT) com> wrote in message news:MPG.1fd4289d383bb87898d667 (AT) msnews (DOT) microsoft.com... Jon Shemitz <jon (AT) midnightbeach (DOT) com> wrote: Put it this way: I might use it for convenience within an internal set of classes, but if I were writing a library I wouldn't implement IDisposable on something that wasn't in *some* way freeing a resource. I do see your point, but I'm not really sure how valid it is, at least in the context of C# and the `using` statement, where you don't actually see a Dispose() call. (Languages like Delphi for .NET that lack a `using` statement are a different story.) If I write a library, it doesn't matter whether I write it in C# or not - it could be used in a different language (eg Delphi.NET) which *doesn't* have a using statement. The way I see it, implementing IDispose in these cases just means that you can use a `using` statement to make your code smaller and less cluttered. I admit there is a certain amount of semantic violence, but there are three reasons I don't think that matters, here. A) Semantic violence matters where there's a possibility of confusion, which I don't think is the case, here. I would, in fact, argue that the smaller code is clearer. Where it's present - but if you end up calling Dispose() explicitly from other languages, surely that would cause confusion. That's why I made my comment about the difference between using it effectively for private use and exposing it as part of a public class. B) There's already a certain amount of fuzziness around the IDispose pattern. with things like streams exporting Close methods instead of Dispose methods. Not usually "instead of" - "as well as". Close() is there for the sake of familiarity with previous APIs, IMO. C) Some of the other system patterns are used pretty loosely, like IEnumerable, with its special casing for arrays, classes that implement GetEnumerator but not IEnumerable, and iterators that don't implement Reset, &c. That's certainly true. Besides, I think I can argue with a straight face that the tiny little IDisposable class that one creates for all the examples above constitute a sort of managed resource that needs to be freed - that you are creating a resource that frees you from the need to explicitly code your 'end' action. You're clearly better able to maintain a straight face than I am ![]() -- Jon Skeet - <skeet (AT) pobox (DOT) com http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
#9
| |||
| |||
|
#10
| |||
| |||
|
|
And I just wanted to toss in another wrench: TransactionScope isn't such a good example anyway because it may use Dispose to free distributed transactional resources. So our use of the C# using statement is actually appropriate here ![]() |
|
Hi Cordell, snip It serves only aesthetical purposes since a try..finally block could easily be coded in its place, providing no guarantees as well. Well, this is where my point about it being a bit more than a 'systactic sugar'/aesthetic comes in. I say this really because of the compile time check that 'using variables' arn't reassigned in any way ... That's a good point. There is some consequential value to using the "using" statement: protection against reassignment. snip Regardless, I like that TransactionScope allows for use of the C# using statement - it looks much nicer and reads better, IMO. Lol ... people really like this point huh , but that IMO, is really a(*very valuable*) side effect rather than a core design requirement. It's important to me that a language's constructs are legible (but not overly verbose as in VB.NET, IMO). I believe legibility is a core design requirement for the authors of C#. It seems that way just from reading some of their blogs. After all, it's not like C# is the CLR - it's a "language" compiler ![]() snip And I just wanted to toss in another wrench: TransactionScope isn't such a good example anyway because it may use Dispose to free distributed transactional resources. So our use of the C# using statement is actually appropriate here ![]() Other, actually nonconforming uses for the C# using statement may have been submitted in this thread but I can't think of any that I use that don't have something unmanaged to be disposed of. Any suggestions? -- Dave Sexton |
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
| |