BitFlipper said:
Sven Groot said:
*snip*

And what if you don't want the object disposed at the end of the scope, because you do want to store a reference somewhere?

 

As I said, OnScopeExit is not related to the GC and it does not dispose the object in any way. Destructors in C++ are often used to perform syncing operations, not just resource cleanup. Just because an object goes out of the scope from where it was created does not mean the object cannot be referenced from anywhere else after the fact, or that it will stop functioning in any way (since OnScopeExit doesn't dispose anything).  This is more used in cases where you need to know exactly when the object goes out of scope from a certain block of code, similar to how you can do it with try/finally or "using" blocks, but without the extra lines of code.  Very useful when a block of code can exit from multiple places. Plus I don't see why this would add overhead since the compiler can check each object and only call OnScopeExit if the object actually overrode the default, empty OnScopeExit call.

 

Edit: The logic is something like this:

  • Was new called on an object? If not, don't do anything further.
  • Did the object override OnScopeExit? If not, don't do anything further.
  • Create a hidden try/finally block (similar to how it is done for lock, using, etc)
  • In the finally block, call OnScopeExit for the object.

So I don't see how this is any more complex than what is already done for lock and using, or how it is going to cause any kind of performance hit. if you don't override OnScopeExit, there is no extra code.

Implementing your idea through a virtual method binds the behavior to every object of that type. This is seldom what we want for clean-up code. E.g., consider Stream. Sometimes I open a file and want to close it within the same function, other times I want it to outlive the current method. I would need two separate types for those behaviors.

 

You've made the behavior an attribute of the type when in fact we want to control it according to the context in which we're using the instance. With your OnScopeExit if I wanted a FileStream that cleans itself up I would need to derive a new type. That's just not a good design.

 

Not to pick on your idea, but try/finally is explicit. "using" is syntactic sugar, but still explicit. Trying to read code that used your scheme would require me to check whether the type I'm using has an override for OnScopeExit and to examine what it did. It's less readable.

 

I don't see the benefit when C# already has "using."