using (object) a Mystery for me!!!

D

Duggi

I used to wonder why MS implemented C# to accept the following code

using (Font f = new Font())
{
// some code here.
}

While the same can be achieved through

{
Font f = new Font()
// some code here.
}

Just making code as a block and create the object inside the block.
Why MS took pain to implement the semantics to understand in C# it as
in first block.

As per my understanding the above code does the following things
1. Creates a block where f is used
2. When code block completes execution, f is garbage collected.

I was wrong. There is one major significant difference between the two
code blocks.

Actually, what ever the object used in the using(object) statement,
has to implement IDisposable. I think by now you got the difference.
The beauty of the using(object) statement is that after the execution
of the using block object.Dispose() will be called by the framework,
releasing all the unmanaged resources.

See below code:

class TestC : IDisposable
{
public void UseLimitedResource()
{
Console.WriteLine("Using limited resource...");
}

void IDisposable.Dispose()
{
// this class uses significant unmanaged resources and are relesed
here.
Console.WriteLine("Disposing limited resource.");
}
}


class Program
{
static void Main(string[] args)
{
using (TestC testC = new TestC())
{
testC.UseLimitedResource();
}

Console.ReadLine();
}
}

However I ran into another BIG doubt that why C# allows the following
code

class Program
{
static void Main(string[] args)
{
TestC testC = new TestC()
using (testC)
{
testC.UseLimitedResource();
}

testC.UseLimitedResource();

Console.ReadLine();
}
}

Object is already disposed, still you can use it, driving to CRASHing
your own applications????

I appriciate your help understanding it properly.

-Cnu
 
I

Ignacio Machin ( .NET/ C# MVP )

I used to wonder why MS implemented C# to accept the following code

using (Font f = new Font())
{
      // some code here.

}

While the same can be achieved through

{
Font f = new Font()
      // some code here.

}

It's nt the same, in the first you are explicitely telling the
compiler to Dispose the instance. If the type you place in the using
does not implement IDisposable yuo get an error:
using (Assembly a = Assembly.GetExecutingAssembly()){
}
You will get an error.

When you declare yuor instance INSDE the block, it simply is marked as
being disposable (if nobody hold a reference to it of course) but the
compile WILL NOT GENERATE code to dispose the instance.
class Program
{
static void Main(string[] args)
      {
TestC testC = new TestC()
            using (testC)
            {
                testC.UseLimitedResource();
            }

testC.UseLimitedResource();

            Console.ReadLine();
       }

}

Object is already disposed, still you can use it, driving to CRASHing
your own applications????

Not really, the object is marked as being disposable, it's not until
the GC runs that the object is REALLY disposed. Do a search for
WeakReference .
Besides your code is clearly a bad code, the compiler cannot prevent
htat kind of code from being written.
 
J

Jon Skeet [C# MVP]

Ignacio Machin ( .NET/ C# MVP ) said:
Not really, the object is marked as being disposable, it's not until
the GC runs that the object is REALLY disposed. Do a search for
WeakReference .
Besides your code is clearly a bad code, the compiler cannot prevent
htat kind of code from being written.

No, it's not "marked as disposable" - it *is* disposed, which is very
different from being garbage collected or finalized.
 
R

raylopez99

Ignacio Machin ( .NET/ C# MVP ) <[email protected]> wrote:
No, it's not "marked as disposable" - it *is* disposed, which is very
different from being garbage collected or finalized.

Whoa! Two MVPs disagreeing! Dangerous! Step back I see a brawl
a'comin'! :)

My newbie answer to the OP is that points 1 and 2 of the OP are sound,
since 'using' is the same as:


'using (X) { //} is equivalent to (pseudo-code):

try { //} finally { if (X.Dispose();}

So 'using' is safer, since you can try a null pointer and it will not
crash your program, it will just trigger the catch or finally block.

RL
 
G

Göran Andersson

Duggi said:
Object is already disposed, still you can use it, driving to CRASHing
your own applications????

The Dispose method is just a method like any other, there is nothing
magical about it that would make it impossible to use the object after
it's called.

Most objects are not very useful once you called Dispose, but that's
because of the code that was put in the Dispose method, not because of
the call in and of itself.
 
J

Jon Skeet [C# MVP]

Duggi said:
Agreed. I think objects that are marked for finalization are garbage
collected when garbage collector is ran, However dispose will be
called then and there itself.

Only if the finalizer is written to call Dispose. Finalization doesn't
*automatically* call Dispose. As far as the runtime is concerned,
IDisposable is just another interface and Dispose is just another
method.
 
M

Mythran

.... >SNIP<
My newbie answer to the OP is that points 1 and 2 of the OP are sound,
since 'using' is the same as:


'using (X) { //} is equivalent to (pseudo-code):

try { //} finally { if (X.Dispose();}

So 'using' is safer, since you can try a null pointer and it will not
crash your program, it will just trigger the catch or finally block.

RL

Close, but no...your pseudo-code is a little off or lacking a little.

using (X) {
// some code here
}

is similar to (but not 100% positive unless we reflect the IL):

// # Compilation check here to ensure X implements IDisposable.
try {
// some code here
} finally {
if (X != null) {
X.Dispose();
}
}

From my tests (again, I have not looked at the IL for this), there are a few
differences to my example than yours (besides the simple compilation errors
from the pseudo-code):

1.) There is a compilation check to make sure X implements IDisposable.
2.) In the finally block, there the code checks to see if X is NOT null.

A third thing that is similar for both, but doesn't really show unless you
see it or *understand* it is that you can declare and create an instance of
X for use ONLY in the using block, while you can't do the same thing in the
try...finally block.

Example:

using (MyClass X = new MyClass()) {
// some code here.
}

while you can't do:
try {
MyClass X = new MyClass();
// some code here.
} finally {
if (X != null) {
X.Dispose();
}
}

Hope this helps a bit more :)

Mythran
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top