maxxxx
maxxxx

Reputation: 123

Alternative syntax for C# using statement to automatically dispose objects?

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.

Upvotes: 5

Views: 7540

Answers (4)

Matthew King
Matthew King

Reputation: 5194

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.

Upvotes: 4

Tod
Tod

Reputation: 8242

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.

Upvotes: 6

David Anderson
David Anderson

Reputation: 13670

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).

Upvotes: 3

Joel Coehoorn
Joel Coehoorn

Reputation: 415830

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.

Upvotes: 7

Related Questions