5

I was wondering if anyone can think of a way to implement a mechanism that works like the using statement in C# but with a cleaner syntax.

In C++/CLR you can write

MyClass NewObject;

MyClass is a managed class here. As soon as the variable goes out of scope Dispose will be called. In essence, it does the same thing C# does with using but in a nicer way.

So, instead of writing

using (MyClass NewObject1=new MyClass())
{
    xxxx;
    using (MyClass NewObject2=new MyClass()
    {
    }
}

(I think this doesn't look very clean and it's also tedious to open a new block for every new variable)

I would prefer something like this:

autodispose MyClass NewObject1=new MyClass();
xxxx;
autodispose MyClass NewObject2=new MyClass();

Does anybody think it would be possible to implement something like this? It seems frameworks for AOP or code contracts use mechanisms that inject code but I am not sure how they do it.

9
  • 2
    using is still cleaner than the alternative (try/finally, blech) Commented Mar 6, 2012 at 20:44
  • 1
    What if MyClass is a managed class that doesn't implement IDisposable? Commented Mar 6, 2012 at 20:48
  • 2
    You're thinking about CLR objects the wrong way. Commented Mar 6, 2012 at 20:50
  • 1
    You get scope with using that you lose with your preference (at least without further decoration) Commented Mar 6, 2012 at 20:57
  • Yes but not as clean as C++/CLI's trick of treating heap managed objects with stack semantics which is what the OP is after. I wish I had an answer. Commented Mar 6, 2012 at 20:59

4 Answers 4

7

MyClass is a managed class here. As soon as the variable goes out of scope Dispose will be called.

That's just not true, even in C++/CLR. My understanding is that C++/CLR still relies on the core .Net garbage collector for managed objects, rather than traditional C++ destructor semantics... and by those rules the object is disposed at some non-deterministic point in the future; it might be immediate... but more likely not. It will probably be fairly soon... but you can't be sure.

Even in the C# world, a using block is reserved for unmanaged resources (ie: anything other than RAM). You don't need to put just any object in a using block: most things can be safely created without one. When you need a using block is when there's something like a network connection, database connection, file handle, gdi resource, system timer, etc wrapped up in the type you're creating.

Sign up to request clarification or add additional context in comments.

3 Comments

I can't speak to C++/CLR, but I would guess that it is at least better at consistently calling an object's destructor when it falls out of scope, no?
@Joel This is not true. In C++/CLI you can treat heap managed objects with stack semantics. This is really "syntactic sugar or sleight of handle" . "To sum up, the heap-allocated object is immediately deleted at the end of the block, rather than lazily garbage collected, and as a consequence, the destructor is called immediately upon deletion." Quotes from Hogenson Foundations of C++/CLI
The Dispose method of a managed object does not destroy the object. It may render the object semantically useless, and may destroy outside references to the object (including the Finalization Queue), but the memory used by the object won't be reclaimed until the next GC cycle regardless.
6

While I don't have answer I feel it's worth writing this up as an answer instead of just comments. The current answer with the most votes is as far as I know incorrect. According to Gordon Hogenson in Foundations of C++/CLI it does support "syntactic sugar or sleight of handle".... "To sum up, the heap-allocated object is immediately deleted at the end of the block, rather than lazily garbage collected, and as a consequence, the destructor is called immediately upon deletion." -emphasis mine, p 63 Stack vs. Heap Semantics

C++ programmers (pre smart pointers) are used to the fact that everything they new they must delete. However, when a C++ programmer creates a local variable, it does not have to be put on the heap. Stack semantics can be used and then the object doesn't have to explicitly deleted.

void Class::SomeMethod()
{ 
   DbConnection connection;  //No memory leak if not deleted
   DbConnection leaky_connection = new DbConnection(); //on the heap will leak if not deleted
}

In C++/CLI it would look a little different for heap allocation:

DbConnection^ connection = gcnew DbConnection();

But since MS knew C++ programmers are used to stack semantics they allow the stack semantic version:

DbConnection connection;

And assuming the existence of :

~DbConnection()
{
   //Close the connection
}

The stack semantic version will immediately call the destructor at the end of the method where connection is used.

I think the difficulty in doing this in C# is for the opposite of why it's allowed in C++/CLI (and here I may get into trouble). C# programmers are used to letting the garbage collector take care of things. They can allocate a local object stick it into a non-local container and not worry that it will go out of scope at the end of the method. The GC knows it's in the collection and it doesn't get prematurely destroyed. C# always deals with object references and you don't explicitly specify heap vs. stack storage. Implementing this "sleight of handle" in C# would probably break a lot of code and expectations.

In fact even the using statement syntax can create unexpected trouble in C#. I wrote up my favorite example of this in When Dispose Throws the Baby Out with the Bathwater a while back.

7 Comments

Tod, thanks for writing this up much more succinctly than I could have done. Personally I don't think what I am trying to do would cause any more problems than using "using". It's the same behavior just with a different syntax. I intentionally didn't propose to copy the C++ stack syntax because that would indeed break a lot of code. I'll have to take a closer look how some frameworks inject code. Maybe I can figure something out.
Regarding the difficulty being "C# programmers are used to letting the GC take care of things" -- you're right, but there's a larger issue. A GC-managed heap is much faster than a normal malloc-style heap, but only if objects have no destructors or finalizers. A GC is most efficient when it can free a large number of objects at once, which cannot happen if a bit of code needs to be executed each time an object is destroyed. In order to support both a GC-managed heap and a deterministic heap, the runtime would need to maintain two heaps, which adds complexity and memory overhead.
Don't forget that my original question was about a different syntax for the using statement without changing the actual behavior. The same applies to C++/CLI. The "stack-like" semantic is just a nicer syntax (to my eyes) but behaves exactly as the using syntax in C# does.
I know, and I do like your question, however, I think in the end what you are after is really just syntactic sugar, basically replacing using (){} with a new autodispose keyword. I think even if you figure it out, it will probably harm maintainability for programmers other than you who are used to ,and expect the using(){} idiom in C#.
Many difficulties in .net stem from the fact that Microsoft seems to have started with the notion that resources should be managed via garbage collection rather than disciplined code, thus building finalizer support into Object and C#, while IDisposable was sort of tacked on. Certain essential features are thus missing, like the ability to take care of an object's fields when a constructor (possibly of a derived class) throws an exception. Further, there needs to be a better defined pattern for handing off responsibility for IDisposable objects.
|
4

This question is almost 9 years old, and there is now a better answer.

C# 8 introduced using declarations

A using declaration is a variable declaration preceded by the using keyword. It tells the compiler that the variable being declared should be disposed at the end of the enclosing scope.

As per the original question, instead of writing:

using (MyClass NewObject1=new MyClass())
{
    // insert more code here;
    using (MyClass NewObject2=new MyClass()
    {
    }
}

you can instead write:

using var newObject1 = new MyClass();
// insert more code here;
using var newObject2 = new MyClass();

The objects will be disposed when they go out of scope.

Comments

3

If you want to compact your using statements for typing brevity, why not do

using (MyClass class1 = new MyClass())
using (MyClass class2 = new MyClass())
using (MyClass class3 = new MyClass()) {
    object xxxx;
    // do some stuff
}

You can save your self some curly braces and a few extra lines since it seems that is what you're after, but its not significant. If you're brevity-OCD

using (var class1 = new MyClass())
using (var class2 = new MyClass())
using (var class3 = new MyClass()) {
    object xxxx;
    // do some stuff
}

By the way, using is a good thing for C#. You get to define the scope of the variable and you know exactly what the scope of that variable is, and when it will end. Where as otherwise, the scope could extend all the way into some other function even (eg. passing a reference to a function, or another object holding a reference to it).

6 Comments

I still don't like the looks of the using statement syntax. With the syntax I propose I still can control the scope of a variable with curly braces if I want to but I don't have to.
You live within the constructs of C# when you use C#. If the constructs of C# don't meet your requirements, then maybe its not the right language for your task. This really isn't a constructive question for SO because this just begs on your personal preference.
I would disagree. I think it IS a good question. One thing I like about C# over C++ is that it's always growing and changing incrementally. If it can borrow a good concept from another language then great, isn't that how we got LINQ? This particular topic may in the end amount to nothing more than a light dusting of syntactic powdered sugar but thinking about the concept of stack vs. heap semantics and how it might make C# more useful (or not) seems worth the bandwidth to me. The whole using/dispose thing feels like a broken GC promise to me.
David, the one thing I miss from C# compared to C++ are destructors that run when an object goes out of scope. You can do so many useful things with that. The using syntax feels just "bolted on" to me. I have done some work with C++/CLI recently and they have solved this much more elegant. So I was wondering if it was possible to achieve something similar in C#. If it wasn't allowed to think about how to make C# better then we wouldn't have frameworks like Moq that push the language to its limits. We also wouldn't have the LINQ syntax.
It really sounds like you both would rather be using C++. I agree about C++ style finalizers, but C# lives within the constraints of the CLR and garbage collector. C++/CLI lives within that constraint for managed objects, but not native. I've written native C++, and C++/CLI (the latter for many years), and you're just sitting on the fence about a using-statement vs a keyword you probably won't ever get in C#. You could create a mechanism to do you want, but it isn't going to boil down to a keyword and you would be interfering with the GC algorithms. Not only that, its more work than using
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.