How can this be? (another GC/Dispose() thread)

  • Thread starter Thread starter Daniel Billingsley
  • Start date Start date
D

Daniel Billingsley

The example code for Memory shows it being used in a using() block. The
documentation for using() says it can only be used on things that implement
Disposable.

Yet there is no Dispose() method for Memory. So, while using(Memory...)
compiles fine, calling .Dispose() in a finally block wouldn't be possible.
Those are supposed to be equivalents, aren't they?

Who can untangle this one?
 
Daniel Billingsley said:
The example code for Memory shows it being used in a using() block. The
documentation for using() says it can only be used on things that implement
Disposable.
For memory? Are you talking about MemoryStream? Streams are disposable, they
just use an explicit interface definition which doesn't appear in normal
intellsense(and is not directly available in C# to my knowledge, however I
think MC++ can call directly). using casts the object to IDisposable, so if
it implements IDisposable it will be able to find and call the method
properly.
 
Ah, that makes perfect sense.

Yes, I meant MemoryStream... not sure exactly how I mistyped that. :)

So, in a finally block you'd have to write something like
((IDisposable)buffer).Dispose

Using() seems much more perty to me. :)

That's assuming, as I think I've heard, that Dispose() is preferable to just
buffer.Close()... right?
 
Daniel,

It really doesn't (nor should it matter). The Dispose method calls the
Close method on the stream.

Hope this helps.
 
Comments inline:


--
Eric Newton
C#/ASP Application Developer
http://ensoft-software.com/
(e-mail address removed)-software.com [remove the first "CC."]

Daniel Billingsley said:
Ah, that makes perfect sense.

Yes, I meant MemoryStream... not sure exactly how I mistyped that. :)

So, in a finally block you'd have to write something like
((IDisposable)buffer).Dispose

actually the using statement tries to cast the instance to IDisposable with
the "as" clause:

try //using( declaration )
{
finally
{
IDisposable disposable = [declaration instance] as IDisposable;
if( disposable != null ) disposable.Dispose();
}
 
Hi Daniel,

Thanks for posting in this group.
In "using Statement"'s documentation, you can find that: The object you
instantiate must implement the System.IDisposable interface.
So actually, the using statement implicit call the IDisposable.Dispose
method.
In IDisposable.Dispose documentation, you will find that by convention,
stream should be closed, so Stream class provided Close method, which calls
the Dispose method.
And the buffer is still available on a MemoryStream once the stream has
been closed. MemoryStream.Close method just closes the stream for reading
and writing.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Eric Newton said:
Comments inline:

(If you're going to put comments inline, please make sure your sig
doesn't come before them - it makes it harder to reply in newsreaders
which don't include anything below the sig separator.)
actually the using statement tries to cast the instance to IDisposable with
the "as" clause:
try //using( declaration )
{
finally
{
IDisposable disposable = [declaration instance] as IDisposable;
if( disposable != null ) disposable.Dispose();
}

No it doesn't. The type used in the using statement must implement
IDisposable anyway, so there's no need to do this. What it *does* do is
test whether or not it was actually initialised. From the C#
specification:

<quote>
A using statement of the form

using (R r1 = new R()) {
r1.F();
}

is precisely equivalent to

R r1 = new R();
try {
r1.F();
}
finally {
if (r1 != null) ((IDisposable)r1).Dispose();
}
</quote>
 
Aren't these two statements contradicting each other somewhat?

My understanding was .Dispose() would do everything .Close() does, but not
vice versa.
 
Hi Daniel,

Thanks for your feedback.
Sorry, I did not see the contradicted two statements, can you point out
them explicitly to me? Thanks.
Acutally, in my last 2 paragraph, I talk about the relation between Dispose
and Close method.
Conventionally, when we manipulate the stream, we will "close" a stream
after everything get done. So .Net provides a same name "close" method for
stream class, which actually calls Dispose method to do the unmanaged
resource releasing. But close method will do more extra stream-related
operations to stream(Because it is a method of stream class), while Dispose
method is a member of IDisposable interface which does not know about
Stream class.
So I do not think ".Dispose() would do everything .Close() does".

In a word, .Dispose method is a member of IDisposable, it is use for
releasing unmanaged resource(It need to be explicit called). .Close method
is a member of Stream class, it will explicit call the .Dispose method, in
addition, it will do some stream correlative operations.

I hope I have explained clearly.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Say WHAT?

IDisposable is an interface, it doesn't implement anything - that is, of
course it doesn't know what specifically will happen in the Dispose()
implementation, by definition. But of course the specific implementation of
Dispose() in the StreamWriter class knows it is a StreamWriter.

The contradiction I see is that you claimed Close() will call Dispose(), but
then also that you can keep working on the object after calling Close(). I
can't see how that's possible.
 
Hi Daniel,

Oh, maybe my original statement is somewhat not precise. I think the reason
the implement of MemoryStream.Dispose did not do everything .Close() does
is that IDisposable.Dispose is used for freeing, releasing, or resetting
unmanaged resources. So it will not do the extra Stream-related work(Such
as control the stream state etc.) of MemoryStream.
For the "the buffer is still available on a MemoryStream once the stream
has been closed", it is actully correct.
MemoryStream.Close only "Closes the stream for reading and writing.", in
which reading means memorystream can read bytes from the stream into your
buffer, writing means that you can write your buffer's bytes into that
stream.
After Closed, you can not do these 2 operations, but because the buffer
under your memorystream class is a managed resource, it has not been
released by Dispose method, it will still been available, so you still can
read bytes from the buffer to your application, I think it will only be
unavailable after this memorystream object was GC collected.

The code snippet below demonstrated this:

private MemoryStream ms;
//Construct the MemoryStream in Form_Load
private void Form1_Load(object sender, System.EventArgs e)
{
int count=10;
byte[] buf=new byte[count];
for(int i=0;i<count;i++)
{
buf=Convert.ToByte(count-i);
}
MemoryStream memstr=new MemoryStream();
this.ms=memstr;
}

private void button1_Click(object sender, System.EventArgs e)
{
try
{
int newcount=7;
byte[] newbuf=new byte[newcount];
newbuf=ms.GetBuffer();
for(int i=0;i<newcount;i++)
{
Console.Write(newbuf.ToString());
}
ms.Close();
newbuf=ms.GetBuffer(); //this works well
ms.Read(newbuf,0,newcount); //this line
will generate exception, because ms was closed for read.
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Hope this helps,

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Changing Close() to Dispose() in your example results in the same error.
That suggests that the same thing has been done to the stream in both cases,
doesn't it? I would think you'd have to show different results after
calling the two methods to demonstrate your point.

Let's go back to the beginning here though...

my point is really a practical one... I think you're suggesting that for
classes that implement Close() it would be preferable to Dispose() in terms
of performing cleanup of the object. Is that right? I've heard the
opposite.
 
Jeffrey Tan said:
Oh, maybe my original statement is somewhat not precise. I think the reason
the implement of MemoryStream.Dispose did not do everything .Close() does
is that IDisposable.Dispose is used for freeing, releasing, or resetting
unmanaged resources. So it will not do the extra Stream-related work(Such
as control the stream state etc.) of MemoryStream.

Yes it will. Dispose() on a MemoryStream *definitely* calls Close().
Here's proof:

using System;
using System.IO;

class Test : MemoryStream
{
static void Main()
{
Test t = new Test();
Console.WriteLine ("About to dispose");
((IDisposable)t).Dispose();
Console.WriteLine ("Done dispose");
GC.KeepAlive(t);
}

public override void Close()
{
Console.WriteLine ("Close called");
}
}

The cast is needed because Stream implements IDisposable explicitly.
 
Hi Jon,

Oh, thanks for your code, yes, it seems that Dispose method really calls
Close method.
Thanks for your correct.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Hi Daniel,

Jon's test project suggest that Dispose method also calls Close method. So
I think these 2 methods actually do the same things.
I did not suggest you use close method instread of dispose. I just point
out that why close method is introduced into the .Net Framework(For
conventional purpose).
The sample I wrote suggest that Close method will only close the stream for
reading and writing, and the buffer of this stream is still available. Not
to demonstrate anything else.
Sorry for any confusion. And also thanks Jon for correct.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Back
Top