473,387 Members | 1,431 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

TextWriter fails on Close() call in destructor

I have a log class that makes a synchronized TextWriter like so, in
the constructor:

StreamWriter sw = new StreamWriter(filename);
tw = TextWriter.Synchronized(sw);

In the destructor, ~MyLogClass(), I call:

tw.WriteLine("some stuff");
tw.Close();

The Close() call throws an exception saying I can't do this on a
closed file. But, I don't close it anywhere! Is the file
automatically closed by the destructor before I get a chance to use
it? Are resources' Dispose() auto-invoked or something? What's
strange is that the WriteLine doesn't throw an exception (although its
contents never make it to the file).

Zytan

Mar 22 '07 #1
54 5116
On Mar 22, 4:58 pm, "Zytan" <zytanlith...@yahoo.comwrote:
I have a log class that makes a synchronized TextWriter like so, in
the constructor:

StreamWriter sw = new StreamWriter(filename);
tw = TextWriter.Synchronized(sw);

In the destructor, ~MyLogClass(), I call:

tw.WriteLine("some stuff");
tw.Close();
That's not a good idea to start with. Finalizers should only deal with
unmanaged resources. Bear in mind that by the time *your* finalizer
runs, the StreamWriter's finalizer may already have run. It sounds
like you may well not want a finalizer at all (they should be very
rare - basically only when you have direct access to unmanaged
resources, eg handles).

Instead, you should implement IDisposable and tell the caller to call
Dispose.
The Close() call throws an exception saying I can't do this on a
closed file. But, I don't close it anywhere! Is the file
automatically closed by the destructor before I get a chance to use
it? Are resources' Dispose() auto-invoked or something? What's
strange is that the WriteLine doesn't throw an exception (although its
contents never make it to the file).
The underlying stream has probably had its finalizer run already.
(Note that this is separate from a Dispose method. Often, and using
MS's pattern, a finalizer will call Dispose, but that's just a matter
of implementation, not something the CLR does for you.)

Jon

Mar 22 '07 #2
Jon, writers do not have a Finalize method. The underlying streams
have Finalize methods to close themselves. The result is that the
writer's buffer is never flushed to the stream before the stream is
closed, resulting in lost data (it's designed this way). I assume
WriteLine executes error free because no attempt is made to flush to
the closed stream.

Zytan, avoid Finalizers for unmanaged code because stuff like this
happens. Try a syntax like:
using (StreamWriter stream = new FileInfo(@"c:\test123").CreateText())
{
stream.WriteLine("blah blah blah");
}
Mar 22 '07 #3
james <ja********@gmail.comwrote:
Jon, writers do not have a Finalize method.
True, but streams do. I should have been more precise in my post.
Calling Close on the writer will call Close on the stream, which may
well have been finalized, hence the error.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 22 '07 #4
No. The error occurs because calling close in the TextWriter flushes
it's buffer to the stream, which may have been finalized. You can
close the stream multiple times with no exception. For instance

tw.Close();
tw.Close();
tw.Close();

is perfectly legit.

Mar 22 '07 #5
james <ja********@gmail.comwrote:
No. The error occurs because calling close in the TextWriter flushes
it's buffer to the stream, which may have been finalized. You can
close the stream multiple times with no exception. For instance

tw.Close();
tw.Close();
tw.Close();

is perfectly legit.
Ah, I see. Thanks for correcting me. I really should read more
carefully :)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 22 '07 #6
I have a log class that makes a synchronized TextWriter like so, in
the constructor:
StreamWriter sw = new StreamWriter(filename);
tw = TextWriter.Synchronized(sw);
In the destructor, ~MyLogClass(), I call:
tw.WriteLine("some stuff");
tw.Close();

That's not a good idea to start with. Finalizers should only deal with
unmanaged resources. Bear in mind that by the time *your* finalizer
runs, the StreamWriter's finalizer may already have run. It sounds
like you may well not want a finalizer at all (they should be very
rare - basically only when you have direct access to unmanaged
resources, eg handles).
Ok, I want a logging method where Trace isn't good enough (I want
formatted logs), so I will write the log as HTML or RTF. The log
should be accessible from any method, so it needs to be 'global', so
it'll be a static class. The static constructor will open the log
file. A WriteLine method will write to it, and flush, to ensure the
data it written in the event of a crash, so I can see what last
happened (slower, yes, I know, but speed isn't an issue). And
sometime before the program ends, the file should close.
Instead, you should implement IDisposable and tell the caller to call
Dispose.
Ok. I will make it use the IDospable interface, thus implementing a
Dispose method, which will call tw.Close(). I'll see if that works.
The Close() call throws an exception saying I can't do this on a
closed file. But, I don't close it anywhere! Is the file
automatically closed by the destructor before I get a chance to use
it? Are resources' Dispose() auto-invoked or something? What's
strange is that the WriteLine doesn't throw an exception (although its
contents never make it to the file).

The underlying stream has probably had its finalizer run already.
(Note that this is separate from a Dispose method. Often, and using
MS's pattern, a finalizer will call Dispose, but that's just a matter
of implementation, not something the CLR does for you.)
Yes, I am vaguely aware of th differences between finalizer (which I
call a d'tor, I hate that C# has c'tors and doesn't use the same term
d'tor), and the Dispose method. Thanks for the explanation.

Zytan

Mar 22 '07 #7
Jon, writers do not have a Finalize method. The underlying streams
have Finalize methods to close themselves. The result is that the
writer's buffer is never flushed to the stream before the stream is
closed, resulting in lost data (it's designed this way). I assume
WriteLine executes error free because no attempt is made to flush to
the closed stream.
I see.
Zytan, avoid Finalizers for unmanaged code because stuff like this
happens. Try a syntax like:
using (StreamWriter stream = new FileInfo(@"c:\test123").CreateText())
{
stream.WriteLine("blah blah blah");
}
Yes, I know all about the using statement, and it's nice, and yeah, I
suppose it indicates that the TextWriter must have a Dispose, since it
forces it to be called, doesn't it? The problem is, is that this is
for logging. The file must close only after I am 100% certain that no
more calls to the static class's methods will be made (to log more
data).

Zytan

Mar 22 '07 #8
No. The error occurs because calling close in the TextWriter flushes
it's buffer to the stream, which may have been finalized. You can
close the stream multiple times with no exception. For instance

tw.Close();
tw.Close();
tw.Close();

is perfectly legit.
So, the TextWriter has not finalized, but the StreamWriter it wrap
has?

I admit I was a little confused with the whole:
StreamWriter sw = new StreamWriter(filename);
tw = TextWriter.Synchronized(sw);

I was hoping that calling
tw.Close();
was all that I had to do, thinking, I was, in effect, calling
sw.Close();

But, apparantly, these are still two distinct objects, even though one
claims to wrap the other.

Zytan

Mar 22 '07 #9
Instead, you should implement IDisposable and tell the caller to call
Dispose.

Ok. I will make it use the IDisposable interface, thus implementing a
Dispose method, which will call tw.Close(). I'll see if that works.
(Let me fix that spelling: IDisposable)

Just as I suspected:
System.IDisposable': static classes cannot implement interfaces

Damn. Static c'tors exist, why not static d'tors? Is there anyway I
can hack one in?

Zytan

Mar 22 '07 #10
Ok, I want a logging method where Trace isn't good enough (I want
formatted logs), so I will write the log as HTML or RTF. The log
should be accessible from any method, so it needs to be 'global', so
it'll be a static class. The static constructor will open the log
file. A WriteLine method will write to it, and flush, to ensure the
data it written in the event of a crash, so I can see what last
happened (slower, yes, I know, but speed isn't an issue). And
sometime before the program ends, the file should close.
Wait, since I'm just writing text to it, and want to format the HTML
or RTF myself (RichTextBox is sloooooooow since it reformats on each
AppendText, and with the nature of logging, it's difficult to group up
a bunch of messages all at once to write in one go), then Trace is
fine, as I can write any text I want to it. I'll have a peak at using
System.Diagnostic.Trace again. I think this is the solution.

Back to the basics.

Zytan

Mar 22 '07 #11
Yes, I am vaguely aware of th differences between finalizer (which I
call a d'tor, I hate that C# has c'tors and doesn't use the same term
d'tor), and the Dispose method. Thanks for the explanation.
Actually, in C++, there exists finalizers and destructors:

class classname {
~classname() {} // destructor
!classname() {} // finalizer
};

So, the distinction is necessary.

Zytan

Mar 22 '07 #12
Ok, I want a logging method where Trace isn't good enough (I want
formatted logs), so I will write the log as HTML or RTF. The log
should be accessible from any method, so it needs to be 'global', so
it'll be a static class. The static constructor will open the log
file. A WriteLine method will write to it, and flush, to ensure the
data it written in the event of a crash, so I can see what last
happened (slower, yes, I know, but speed isn't an issue). And
sometime before the program ends, the file should close.
I tried making a hack of a static destructor (by making the class non-
static, and making a static variable that is an instance of the class,
thus, the destructor will be called on it when it goes bye bye), and
even then, the same error occurs.

The underlying stream must be finalized before I get a chance to stab
at it.

Since I have this hack of a destructor call, by making the class non-
static, it means I can now try IDisposable, and implement Dispose.
I'll try that now.

Zytan

Mar 23 '07 #13
The underlying stream must be finalized before I get a chance to stab
at it.

Since I have this hack of a destructor call, by making the class non-
static, it means I can now try IDisposable, and implement Dispose.
I'll try that now.
I have no idea how to make it call Dispose() automatically. Dispose()
is so that I can 'destruct' the object manually when I want, so this
really does nothing. The finalizer is auto called. It's just called
too late.

HOW can it be called on an object, when I still have another variable
that is alive which wraps it? I need to get rid of the wrapper, I
think, and deal with it directly.

(Since the wrapper provides thread safety, I'll have to implement that
myself.)

Zytan

Mar 23 '07 #14
HOW can it be called on an object, when I still have another variable
that is alive which wraps it? I need to get rid of the wrapper, I
think, and deal with it directly.
Nope, even when I do that, it is finalized when I make the call to
streamWriter.Flush(); A call to streamWrite.WriteLine("xxx"); works
fine (but doesn't get written) immediately before the call to Flush();

I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself. Why is my code even still running
when C# has already finalized some of my variables?

Zytan

Mar 23 '07 #15
Zytan <zy**********@yahoo.comwrote:
So, the TextWriter has not finalized, but the StreamWriter it wrap
has?
No. Neither of them has.

So, there are four objects involved:

1) Yours - with a finalizer
2) The original StreamWriter - no finalizer
3) The TextWriter - no finalizer
4) The Stream underlying the StreamWriter - with a finalizer

Your finalizer was calling Close on the TextWriter, which was calling
Close on the StreamWriter, which was trying to flush its buffer - and
that's what was wrong.
I admit I was a little confused with the whole:
StreamWriter sw = new StreamWriter(filename);
tw = TextWriter.Synchronized(sw);

I was hoping that calling
tw.Close();
was all that I had to do, thinking, I was, in effect, calling
sw.Close();
Yes, you are - the call will be propagated.
But, apparantly, these are still two distinct objects, even though one
claims to wrap the other.
They're still two distinct objects, but the TextWriter has a reference
to the StreamWriter, and it just proxies calls onto the StreamWriter,
with appropriate synchronization.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 23 '07 #16
Zytan <zy**********@yahoo.comwrote:
Instead, you should implement IDisposable and tell the caller to call
Dispose.
Ok. I will make it use the IDisposable interface, thus implementing a
Dispose method, which will call tw.Close(). I'll see if that works.

(Let me fix that spelling: IDisposable)

Just as I suspected:
System.IDisposable': static classes cannot implement interfaces

Damn. Static c'tors exist, why not static d'tors?
Because classes are initialized, but never finalized.
Is there anyway I can hack one in?
No. I suggest you just flush your TextWriter after each call, and let
the OS close the handle automatically when the program exits.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 23 '07 #17
Zytan <zy**********@yahoo.comwrote:
I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself. Why is my code even still running
when C# has already finalized some of my variables?
What else could it do? You could have two objects with references to
each other, but no other references to them. *One* of them has to be
finalized before the other, doesn't it?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 23 '07 #18
Zytan wrote:
>HOW can it be called on an object, when I still have another variable
that is alive which wraps it? I need to get rid of the wrapper, I
think, and deal with it directly.

Nope, even when I do that, it is finalized when I make the call to
streamWriter.Flush(); A call to streamWrite.WriteLine("xxx"); works
fine (but doesn't get written) immediately before the call to Flush();

I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself.
The reason is that there is no finalizing dependency that tells the
memory management that one object has to be finalized before the other.
Why is my code even still running
when C# has already finalized some of my variables?
Because it's calling the finalizers after your main code has finished.
You can't predict when the objects will be finalized, so theoretically
the finalizer may be executed a long time after the main code has finished.
Why not make an object that works in two states? While the Page class
exists, the file is open, and in the Dispose method of the Page, call
Dispose on the object that will close the log file and change the state
of the object. Any writes to the object after that will be done by
opening the file, write the text and the close the file.

--
Göran Andersson
_____
http://www.guffa.com
Mar 23 '07 #19
So, the TextWriter has not finalized, but the StreamWriter it wrap
has?

No. Neither of them has.

So, there are four objects involved:

1) Yours - with a finalizer
2) The original StreamWriter - no finalizer
3) The TextWriter - no finalizer
4) The Stream underlying the StreamWriter - with a finalizer

Your finalizer was calling Close on the TextWriter, which was calling
Close on the StreamWriter, which was trying to flush its buffer - and
that's what was wrong.
Ok, right, thanks for the clarification. It's hard to understand
everything when I am dealing with a wrapper of a wrapper of an object
I am not well versed in.

Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/lib...73(VS.71).aspx
StreamWriter.Finalize Method

And this page implies that TextWriter also has a finalizer:
http://msdn2.microsoft.com/en-us/library/ms227564.aspx
TextWriter.Dispose Method ()
"Always call Dispose before you release your last reference to the
TextWriter. Otherwise, the resources it is using will not be freed
until the garbage collector calls the TextWriter object's Finalize
method."

One question: Is it ok for me NOT to call .Close() or .Dispose() on
the StreamWriter or TextWriter, and let the GC do its work when the
application closes? Presumably, this will properly close the file, as
the GC does call the finalizer on both of them, which does the clean
up work?
But, apparantly, these are still two distinct objects, even though one
claims to wrap the other.

They're still two distinct objects, but the TextWriter has a reference
to the StreamWriter, and it just proxies calls onto the StreamWriter,
with appropriate synchronization.
Right.

Thanks again, Jon.

Zytan

Mar 23 '07 #20
Just as I suspected:
System.IDisposable': static classes cannot implement interfaces
Damn. Static c'tors exist, why not static d'tors?

Because classes are initialized, but never finalized.
To be clear, you meant:
"Because *static* classes are initialized, but never finalized."

But, why aren't they? I'd like to know the reasons why, although it
is futile, since it doesn't change reality.

In Turbo Pascal, which the C# designer made, you could invoke a clean
up process on exit, which would be invoked in the 'static
constructor', and thus have a 'static destructor'. I know you can do
something like this with the DomainUnload event, and I am assuming is
much the same thing. I fear, though, it doesn't help me, since my
underlying Stream will still be finalized before it ever gets called.
I have not tested this, yet, though.
Is there anyway I can hack one in?

No. I suggest you just flush your TextWriter after each call, and let
the OS close the handle automatically when the program exits.
I found a hack: Make the class non-static, instantiate an instance
using a private instance c'tor within the static c'tor, thus the
finalizer will run. And I tried this, and still my Stream is
finalized before I get to poke at it. Besides, I hate hacks.

The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.

Zytan

Mar 23 '07 #21
I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself. Why is my code even still running
when C# has already finalized some of my variables?

What else could it do? You could have two objects with references to
each other, but no other references to them. *One* of them has to be
finalized before the other, doesn't it?
Yes, true.

My point is: Can't it wait to clean my dinner plate until after I am
done eating?

Zytan

Mar 23 '07 #22
My point is: Can't it wait to clean my dinner plate until after I am
done eating?
Hm, but if we're both eating off each other's plates, and we are
waiting for each other to stab before we grab the last bite, then
there's a deadlock. I suppose the mother has to step in at this
point.

I don't believe this is the situation I've created, though.

Zytan

Mar 23 '07 #23
I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself.

The reason is that there is no finalizing dependency that tells the
memory management that one object has to be finalized before the other.
Right. My object clean up code is just as likely to be run first as
another object's clean up code. I guess I was naively thinking the GC
knew which object 'owned' which other object, and thus could guarantee
that all of my objects exist until I am done myself.
Why is my code even still running
when C# has already finalized some of my variables?

Because it's calling the finalizers after your main code has finished.
You can't predict when the objects will be finalized, so theoretically
the finalizer may be executed a long time after the main code has finished.
Right.
Why not make an object that works in two states? While the Page class
exists, the file is open, and in the Dispose method of the Page, call
Dispose on the object that will close the log file and change the state
of the object. Any writes to the object after that will be done by
opening the file, write the text and the close the file.
Interesting solution, to open and append to the file if it is already
closed.

When would Dispose be called, though? I just want the logging file to
be open as long as possible.

Zytan

Mar 23 '07 #24
Zytan wrote:
One question: Is it ok for me NOT to call .Close() or .Dispose() on
the StreamWriter or TextWriter, and let the GC do its work when the
application closes? Presumably, this will properly close the file, as
the GC does call the finalizer on both of them, which does the clean
up work?
I wouldn't depend on it, and certainly not when you've got potential
buffer issues. For example, a buffer in StreamWriter might not be
flushed to the underlying stream, and if the underlying stream gets
disposed first, then you lose the last bit of data you wrote. Not good.

If it implements IDisposable, my general rule is: dispose of it.

GC is for memory management, not resource management.
Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/lib...73(VS.71).aspx
StreamWriter.Finalize Method
It most likely makes a best-effort to flush its buffers to the
underlying stream, hoping against hope that the stream hasn't already
been finalized.

Read this too:

http://msdn2.microsoft.com/en-us/lib...36(VS.80).aspx

-- Barry

--
http://barrkel.blogspot.com/
Mar 23 '07 #25
Zytan wrote:
>>I can't believe C# doesn't give me access to dispose of my own objects
before it finalizes them itself.
The reason is that there is no finalizing dependency that tells the
memory management that one object has to be finalized before the other.

Right. My object clean up code is just as likely to be run first as
another object's clean up code. I guess I was naively thinking the GC
knew which object 'owned' which other object, and thus could guarantee
that all of my objects exist until I am done myself.
It's easy to think of one's own code as special, but the finalizer you
wrote yourself is not treated differently from any other.

There is no way that objects can own each other. They often reference
each other, which would cause a deadlock in the garbage collection if it
would consider the references. A Form object has a reference to a
ControlCollection, which contains a reference to a Control, which has a
reference back to the Form.

Often things doesn't really make sense until you realise that the
alternatives make even less sense. :)
>Why not make an object that works in two states? While the Page class
exists, the file is open, and in the Dispose method of the Page, call
Dispose on the object that will close the log file and change the state
of the object. Any writes to the object after that will be done by
opening the file, write the text and the close the file.

Interesting solution, to open and append to the file if it is already
closed.

When would Dispose be called, though? I just want the logging file to
be open as long as possible.
It doesn't really matter. As long as you have the reference to the
object, it's not garbage collected. You can dispose at the end of the
Main method of your program.

--
Göran Andersson
_____
http://www.guffa.com
Mar 23 '07 #26
Zytan <zy**********@yahoo.comwrote:
Just as I suspected:
System.IDisposable': static classes cannot implement interfaces
Damn. Static c'tors exist, why not static d'tors?
Because classes are initialized, but never finalized.

To be clear, you meant:
"Because *static* classes are initialized, but never finalized."
No, I meant classes. Classes themselves are never finalized. Instances
of classes are finalized.
But, why aren't they? I'd like to know the reasons why, although it
is futile, since it doesn't change reality.
It's just not something that makes much sense - it would only be the
equivalent of adding a handler to the AppDomain unloading event, but
would be less deterministic.
In Turbo Pascal, which the C# designer made, you could invoke a clean
up process on exit, which would be invoked in the 'static
constructor', and thus have a 'static destructor'. I know you can do
something like this with the DomainUnload event, and I am assuming is
much the same thing. I fear, though, it doesn't help me, since my
underlying Stream will still be finalized before it ever gets called.
I have not tested this, yet, though.
Don't forget that while Anders designed C#, he didn't design .NET
itself, and as far as I'm aware (and I could well be wrong) there's no
idea of a static finalizer for types in the CLR.
Is there anyway I can hack one in?
No. I suggest you just flush your TextWriter after each call, and let
the OS close the handle automatically when the program exits.

I found a hack: Make the class non-static, instantiate an instance
using a private instance c'tor within the static c'tor, thus the
finalizer will run. And I tried this, and still my Stream is
finalized before I get to poke at it. Besides, I hate hacks.
Indeed.
The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.
I'm not sure whether it's guaranteed that DomainUnload will be
triggered before static members become eligible for garbage collection
- worth checking out.

I still prefer the idea of flushing the TextWriter after each call
though.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 23 '07 #27
Zytan <zy**********@yahoo.comwrote:
Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/lib...73(VS.71).aspx
StreamWriter.Finalize Method

And this page implies that TextWriter also has a finalizer:
http://msdn2.microsoft.com/en-us/library/ms227564.aspx
TextWriter.Dispose Method ()
"Always call Dispose before you release your last reference to the
TextWriter. Otherwise, the resources it is using will not be freed
until the garbage collector calls the TextWriter object's Finalize
method."
Interesting. Using Reflector, I can't find any evidence of a finalizer
on either TextWriter or StreamWriter. It's possible I'm missing
something, but it's also more than possible that MSDN is incorrect.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 23 '07 #28
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP************************@msnews.microsoft.c om...
Zytan <zy**********@yahoo.comwrote:
>Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/lib...73(VS.71).aspx
StreamWriter.Finalize Method

And this page implies that TextWriter also has a finalizer:
http://msdn2.microsoft.com/en-us/library/ms227564.aspx
TextWriter.Dispose Method ()
"Always call Dispose before you release your last reference to the
TextWriter. Otherwise, the resources it is using will not be freed
until the garbage collector calls the TextWriter object's Finalize
method."

Interesting. Using Reflector, I can't find any evidence of a finalizer
on either TextWriter or StreamWriter. It's possible I'm missing
something, but it's also more than possible that MSDN is incorrect.
V1.1 StreamWriter had a finalizer, this one has been removed since V2.0.

Willy.
Mar 23 '07 #29
One question: Is it ok for me NOT to call .Close() or .Dispose() on
the StreamWriter or TextWriter, and let the GC do its work when the
application closes? Presumably, this will properly close the file, as
the GC does call the finalizer on both of them, which does the clean
up work?

I wouldn't depend on it, and certainly not when you've got potential
buffer issues. For example, a buffer in StreamWriter might not be
flushed to the underlying stream, and if the underlying stream gets
disposed first, then you lose the last bit of data you wrote. Not good.
For my logger, I flush everything immediately after it is written, so
that the log contains all possible information when a crash occurs, in
case the crash shuts down the app before all data can be flushed. So,
I am not worrying about flushing issues.
If it implements IDisposable, my general rule is: dispose of it.
I agree. But this isn't a typical situation. I can't Dispose of my
object since the system has already finalized the underlying stream
that my Dispose method wants to use. It defeats the purpose. I wish
it would wait for me to dispose of my obects, and remove references to
them, before it finalizes them.

Maybe if I had direct access to the stream itself, it would wait? The
problem with wrappers (StreamWriter) is that I am not sure what it's
doing, and if that has any effect. I cannot see why a wrapper would
release a reference to an object when itself has not finalized, yet,
though. Somehow, the Stream just gets finalized.
GC is for memory management, not resource management.
Right.
Read this too:

http://msdn2.microsoft.com/en-us/lib...36(VS.80).aspx
Thanks, Barry. This is the relevant part:

"If neither of these solutions can be used (for example, if a
StreamWriter is stored in a static variable and you cannot easily run
code at the end of its lifetime), then calling Flush on the
StreamWriter after its last use or setting the AutoFlush property to
true before its first use should avoid this problem."

Which is what I do.
The only other possible solution is to have my finalizer REOPEN the
file, and do whatever it has to do with it (like writing EOF
terminators for that file type, like "</HTML>"), and then close it.
But, since I have nothing to write on close, all I have to do it
call .Close(). So, it's pointless.

You recommend that I dispose of the object, since the GC is for memory
management, not resources, but, the GC has already stepped in and
handled my resource for me!

Zytan

Mar 23 '07 #30
No, I meant classes. Classes themselves are never finalized. Instances
of classes are finalized.
Oh, ok. Right.
But, why aren't they? I'd like to know the reasons why, although it
is futile, since it doesn't change reality.

It's just not something that makes much sense - it would only be the
equivalent of adding a handler to the AppDomain unloading event, but
would be less deterministic.
I guess I need something to be deterministic. The problem with a
logger is that it is almost a part of the application overhead. Kind
of like how C++ ensures that the input and output streams are
guaranteed to be available, even though the language states that
(otherwise) there's no particular order chosen. But, this forced
stated makes everything work, since it just doesn't make sense to have
the streams initialized after your own code. And they work right
until the end, so destructors can write to the screen. This is what I
need. It looks like using Trace is the only option. Everything else
is a hack. Unfortunately with Trace, it makes it difficult to ALSO
display the log file onscreen at runtime.
Don't forget that while Anders designed C#, he didn't design .NET
itself, and as far as I'm aware (and I could well be wrong) there's no
idea of a static finalizer for types in the CLR.
Ok. And, it was a kind of 'hack' in Turbo Pascal, as well. It was
basically DomainUnload.
The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.

I'm not sure whether it's guaranteed that DomainUnload will be
triggered before static members become eligible for garbage collection
- worth checking out.
I really should check this out, yes.
I still prefer the idea of flushing the TextWriter after each call
though.
Me, too. It's good enough, I think for what I need. I'll stick with
this.

As long as... TextWriter / StreamWriter is cleaned up propely without
a call to Close(). Considering the underlying Stream is already
finalized before I get a chance to call Close(), I think all is well.

Zytan

Mar 23 '07 #31
It's easy to think of one's own code as special, but the finalizer you
wrote yourself is not treated differently from any other.
yup.
There is no way that objects can own each other. They often reference
each other, which would cause a deadlock in the garbage collection if it
would consider the references. A Form object has a reference to a
ControlCollection, which contains a reference to a Control, which has a
reference back to the Form.
Wow, i see, so this happens far more often than most (I) would
realize.
Often things doesn't really make sense until you realise that the
alternatives make even less sense. :)
I agree, I run into this all the time with programming. And it
catches even the smartest among us.
When would Dispose be called, though? I just want the logging file to
be open as long as possible.

It doesn't really matter. As long as you have the reference to the
object, it's not garbage collected.
Yes, except in your Finalizer :)
You can dispose at the end of the
Main method of your program.
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).

Zytan

Mar 23 '07 #32
"Zytan" <zy**********@yahoo.comwrote in message
news:11**********************@p15g2000hsd.googlegr oups.com...
I can't believe C# doesn't give me access to dispose of my own
objects
before it finalizes them itself. Why is my code even still running
when C# has already finalized some of my variables?

What else could it do? You could have two objects with references to
each other, but no other references to them. *One* of them has to be
finalized before the other, doesn't it?

Yes, true.

My point is: Can't it wait to clean my dinner plate until after I am
done eating?
The problem is...
You were done eating. (the program was shutting down)
You had left the restaurant , and the bus boy was cleaning up.
Only THEN did you try to take another bite.

Can you really blame the bus boy????....I mean the door was locked
and you had gone home!!

If you really want to continue with this approach (as opposed to another
solution) Then I would Manually force a cleanup before exiting the
program.

static void Main()
{
try
{
Logger.Init(); //
Run Program
}
finally
{
Logger.Cleanup();
}
}

Or something like this

Bill
Mar 23 '07 #33
Have you considered opening and closing the file EVERY time you log
something.
I did something like this myself a few years ago.
It performed OK too.

Bill

"Zytan" <zy**********@yahoo.comwrote in message
news:11*********************@n76g2000hsh.googlegro ups.com...
>No, I meant classes. Classes themselves are never finalized.
Instances
of classes are finalized.

Oh, ok. Right.
But, why aren't they? I'd like to know the reasons why, although
it
is futile, since it doesn't change reality.

It's just not something that makes much sense - it would only be the
equivalent of adding a handler to the AppDomain unloading event, but
would be less deterministic.

I guess I need something to be deterministic. The problem with a
logger is that it is almost a part of the application overhead. Kind
of like how C++ ensures that the input and output streams are
guaranteed to be available, even though the language states that
(otherwise) there's no particular order chosen. But, this forced
stated makes everything work, since it just doesn't make sense to have
the streams initialized after your own code. And they work right
until the end, so destructors can write to the screen. This is what I
need. It looks like using Trace is the only option. Everything else
is a hack. Unfortunately with Trace, it makes it difficult to ALSO
display the log file onscreen at runtime.
>Don't forget that while Anders designed C#, he didn't design .NET
itself, and as far as I'm aware (and I could well be wrong) there's
no
idea of a static finalizer for types in the CLR.

Ok. And, it was a kind of 'hack' in Turbo Pascal, as well. It was
basically DomainUnload.
The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.

I'm not sure whether it's guaranteed that DomainUnload will be
triggered before static members become eligible for garbage
collection
- worth checking out.

I really should check this out, yes.
>I still prefer the idea of flushing the TextWriter after each call
though.

Me, too. It's good enough, I think for what I need. I'll stick with
this.

As long as... TextWriter / StreamWriter is cleaned up propely without
a call to Close(). Considering the underlying Stream is already
finalized before I get a chance to call Close(), I think all is well.

Zytan

Mar 24 '07 #34
Zytan wrote:
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).
You can create an instance of it in the main method and use a static
method in the class for writing to the file. The static method can
determine if there is an active instance of the class or not, and use it
if it's there.

--
Göran Andersson
_____
http://www.guffa.com
Mar 24 '07 #35
Zytan wrote:
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).
You can create an instance of it in the main method and use a static
method in the class for writing to the file. The static method can
determine if there is an active instance of the class or not, and use it
if it's there.

--
Göran Andersson
_____
http://www.guffa.com
Mar 24 '07 #36
Bill Butler <qw****@asdf.comwrote:
Have you considered opening and closing the file EVERY time you log
something.
I did something like this myself a few years ago.
It performed OK too.
Alternatively (and I should have pointed this out earlier) - use a
tried and tested logging library like Log4Net.
http://logging.apache.org/log4net/

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 24 '07 #37
Zytan wrote:
I agree. But this isn't a typical situation. I can't Dispose of my
object since the system has already finalized the underlying stream
that my Dispose method wants to use.
You need to keep it alive then, until you do dispose of it, by rooting
it somewhere, either in a local variable low down on the call stack, or
in a static field.
Maybe if I had direct access to the stream itself, it would wait? The
problem with wrappers (StreamWriter) is that I am not sure what it's
doing, and if that has any effect.
No. The GC follows the reference from the StreamWriter to the underlying
Stream. If you keep the StreamWriter alive, the underlying Stream is
kept alive.
I cannot see why a wrapper would
release a reference to an object when itself has not finalized, yet,
though. Somehow, the Stream just gets finalized.
If both Stream and StreamWriter are not ultimately kept alive, then they
both need to be finalized. Which one gets finalized first is
non-deterministic.
You recommend that I dispose of the object, since the GC is for memory
management, not resources, but, the GC has already stepped in and
handled my resource for me!
It has, because you haven't kept the objects rooted!

-- Barry

--
http://barrkel.blogspot.com/
Mar 24 '07 #38
You need to keep it alive then, until you do dispose of it, by rooting
it somewhere, either in a local variable low down on the call stack, or
in a static field.
This is what I have:

static class LogFile
{
private static TextWriter m_twSynch;
...
}

Isn't that rooted? How can I 'root' it more deeply?
No. The GC follows the reference from the StreamWriter to the underlying
Stream. If you keep the StreamWriter alive, the underlying Stream is
kept alive.
Ok, that's what I thought.
You recommend that I dispose of the object, since the GC is for memory
management, not resources, but, the GC has already stepped in and
handled my resource for me!

It has, because you haven't kept the objects rooted!
Please tell me how I can root them! I believe I have been rooting
them, as you've suggested, all along.

Thanks, Barry!

Zytan

Mar 27 '07 #39
Have you considered opening and closing the file EVERY time you log
something.
I did something like this myself a few years ago.
It performed OK too.
Bill, I know this could work, since my first log effort was to not
write anything out until the finalizer. And of course, it can open,
write, close, just fine.

Since I could, and want to, catch unhandled exceptions, I could just
delay the write until then, I suppose.

Thanks, Bill.

Zytan

Mar 27 '07 #40
Alternatively (and I should have pointed this out earlier) - use a
tried and tested logging library like Log4Net.http://logging.apache.org/log4net/
I've ran across this before. I hate using other people's code. I'd
rather learn the language myself, and code it myself, this way, I
learn. And I can upgrade as I need to. But, yes, beyond a certain
point, I just gotta do what works. Letting the file close itself is
ok for me. I don't care that I can't write my </HTMLat the end.
(Which is something I couldn't do even if I opened/closed the file on
each log access, so no difference)

Zytan

Mar 27 '07 #41
Alternatively (and I should have pointed this out earlier) - use a
tried and tested logging library like Log4Net.http://logging.apache.org/log4net/
I've ran across this before. I hate using other people's code. I'd
rather learn the language myself, and code it myself, this way, I
learn. And I can upgrade as I need to. But, yes, beyond a certain
point, I just gotta do what works. Letting the file close itself is
ok for me. I don't care that I can't write my </HTMLat the end.
(Which is something I couldn't do even if I opened/closed the file on
each log access, so no difference)

Zytan

Mar 27 '07 #42
If you really want to continue with this approach (as opposed to another
solution) Then I would Manually force a cleanup before exiting the
program.

static void Main()
{
try
{
Logger.Init(); //
Run Program
}
finally
{
Logger.Cleanup();
}
}
The only problem is that not every class in the app can call
Logger.Write() like this.

Zytan

Mar 27 '07 #43
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).

You can create an instance of it in the main method and use a static
method in the class for writing to the file. The static method can
determine if there is an active instance of the class or not, and use it
if it's there.
Yes, that's true. I guess I lied. Even in this case, the finalizer
is run before I can write out my last bit. But then again, I could
just reopen and append to the file. So, I guess this is good enough.

Thanks for all your help!

Zytan

Mar 27 '07 #44
"Zytan" <zy**********@gmail.comwrote in message
news:11**********************@n59g2000hsh.googlegr oups.com...
>If you really want to continue with this approach (as opposed to
another
solution) Then I would Manually force a cleanup before exiting the
program.

static void Main()
{
try
{
Logger.Init(); //
Run Program
}
finally
{
Logger.Cleanup();
}
}

The only problem is that not every class in the app can call
Logger.Write() like this.
Why not?
Logger.Write() could easily be a static method accessible from anywhere.
Bill
Mar 27 '07 #45
Zytan <zy**********@gmail.comwrote:
Alternatively (and I should have pointed this out earlier) - use a
tried and tested logging library like Log4Net.http://logging.apache.org/log4net/

I've ran across this before. I hate using other people's code.
And yet you're using Microsoft's all the time. If you dismiss all third
party libraries, you'll end up reinventing a lot of wheels.
I'd rather learn the language myself, and code it myself, this way, I
learn.
Log4net is open source - so download the source and see how they do it.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 27 '07 #46
I've ran across this before. I hate using other people's code.
>
And yet you're using Microsoft's all the time. If you dismiss all third
party libraries, you'll end up reinventing a lot of wheels.
I have no choice with Microsoft, and it is far, far more tested than
such 3rd party code. I don't think that's a fair comparison. In
general, open source software doesn't have great quality, from what
I've seen.

I agree reinventing the wheel is bad, in some ways. But, not in terms
of learning. Also, with your own code, you can fix it when things go
bad. Of course, with open source, you can do this, too.
I'd rather learn the language myself, and code it myself, this way, I
learn.

Log4net is open source - so download the source and see how they do it.
Good idea. I would be interested in their ideas.

Thanks,

Zytan

Mar 27 '07 #47
The only problem is that not every class in the app can call
Logger.Write() like this.

Why not?
Logger.Write() could easily be a static method accessible from anywhere.
Yes, that's true.

But, I guess this doesn't solve all problems, since still, the stream
finalizes before my class finalizes (someone mentioned that I didn't
'root' my stream deep enough, and that's why it's finalized before I
am done with it, but it's a static data member in the class -- how
much more rooted can it be?). So, the "cleaning up nicely" puspose
of the finalizer is defeated, since it's already cleaned up. Thus, I
don't need a finalizer. So, what is left is nothing different than
what I already have -- a pure static class.

If I find that I need to log something after the stream has closed,
I'll have redo the function to reopen the file and append, but, so
far, I don't.

Zytan

Mar 27 '07 #48
Zytan wrote:
This is what I have:

static class LogFile
{
private static TextWriter m_twSynch;
...
}

Isn't that rooted? How can I 'root' it more deeply?
Yes it is, until the final non-background thread exits.
Please tell me how I can root them! I believe I have been rooting
them, as you've suggested, all along.
The final thing I'd say is to be sure that you close up these log files
before your main thread exits - e.g. in the Main method, etc., or
similar for a hosted environment - e.g. in an implementation
IHttpModule.Dispose if it's a module in ASP.NET, or hooked to
HttpApplication.Disposed event, etc.

I can't be more specific on ASP.NET because most work I've done with it
was at a relatively low level, at the IHttpAsyncHandler level.

I suspect part of your problem is that whenever you're closing the log
files etc., it's too late. Where are you currently doing it?

-- Barry

--
http://barrkel.blogspot.com/
Mar 27 '07 #49
static class LogFile
{
private static TextWriter m_twSynch;
...
}
Isn't that rooted? How can I 'root' it more deeply?

Yes it is, until the final non-background thread exits.
Ok.
Please tell me how I can root them! I believe I have been rooting
them, as you've suggested, all along.

The final thing I'd say is to be sure that you close up these log files
before your main thread exits - e.g. in the Main method, etc., or
similar for a hosted environment - e.g. in an implementation
IHttpModule.Dispose if it's a module in ASP.NET, or hooked to
HttpApplication.Disposed event, etc.
Well, just imagine that, inside of functions all over the place, there
are calls to LogClass.WriteLine() just as there are Debug.Assert() and
Debug.WriteLine() everywhere. So, where would I call
LogClass.CloseFile()? I suppose at the end of Main(). But, this
isn't my problem, really... if the system is closing the streams
itself, then I really don't have an issue with that. My only issue
was that my own finalizer wanted to say goodbye before it closed, but
it's too late. I know I can solve this by reopening & appending, but
I really don't need to say goodbyte, I'll just leave it closed. I'm
happy.
I suspect part of your problem is that whenever you're closing the log
files etc., it's too late. Where are you currently doing it?
Well, the only problem is that I wanted to write out </HTMLthen
close the stream. But the stream is already closed by the time the
finalizer is run. Since I don't really care that </HTMLis there or
not, I'm not bothered by this.

But, if I really wanted this, I could make a LogClass.CloseFile()
method that Main() calls, and it could do this. Then I may run into
an issue of LogClass.WriteLine() being called in some class after this
happens (say, in its finalizer), so, even in that case, it's best just
to let the system clean up. There's no 100% sure fire way to write </
HTMLat the end after everyone is done, I think. Even if I used a
listener for Debug.Trace, I doubt there's a place I can run my
Trace.WriteLine("</HTML>") after everyone else is done with it, since,
as someone said, my code isn't special.

Thanks, Barry

Please no worries, my solution is fine for my need as is, now. I'll
let the system close the stream itself.

Zytan

Mar 27 '07 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: D | last post by:
I have a winforms app that I'm reading some records from a datareader and writing them out to a file like so SqlDataReader dataReader = sqlCommand.ExecuteReader(); TextWriter textWriter = new...
2
by: kengtung | last post by:
Greetings all, I just started programming with C# (.Net FW 1.1) last year and still learning. Previously I am using VB 6.0. Recently, in one application, I encountered a C# error "Cannot write...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.