C# Garbage Collection & StreamWriter.Close()

HavocXphere

Honorary Master
Joined
Oct 19, 2007
Messages
33,153
Reaction score
1,297
Location
Europe
Because I'm not used to languages with garbage collection I read up on it:
Here
And Here

Very nice. I also learned that I must Close() the StreamWriter myself or risk data loss. Fine. This causes a new problem though:

Code:
            try
            {
                StreamWriter SR = new StreamWriter(@"C:\testout.txt");
                SR.WriteLine(@"Testing");                
            }
            catch (Exception E)
            {
                Console.WriteLine(E.Message);
            }
            finally
            {
                SR.Close();
                Console.Read();
            }

This fails to compile at SR.Close() with:
Code:
The name 'SR' does not exist in the current context

My option as far as I can see are:
  1. Move the Close() to the try block <=== MSDN examples do this
  2. Move the new StreamWriter out of the try block
Either way I lose some of the benefit of the try..finally structure.

Solutions? Or just accept it?
Thanks
 
What if you put the streamwriter in a Using statement,that way you don't need to call the close function?
As for risk of data loss, I'd need to read up on it to understand.
 
Before reading, I'm not a C# guru, but I have some Java background. With that disclaimer...

What is the application?

This is a BAD way to write this code. In any enterprise situation, you shouldn't rely on being able to control GC.

Option 1 will not give you the benefits of the finally {} clause; option 2 will. Just declare the StreamWriter outside the try block.
 
Just declare the StreamWriter outside the try block.
That was my initial reaction too because that is how its done in Delphi. Declare it outside & then open the file inside the try to catch exceptions. I can't see a way to split it that way in c# though.

Code:
            StreamWriter SR;
            try
            {
                SR = new StreamWriter(@"C:\testout.txt");
                SR.WriteLine(@"Testing");               
            }
            catch (Exception E)
            {
                Console.WriteLine(E.Message);
            }
            finally
            {
                SR.Close();
                Console.Read();
            }

Which gives me "Use of unassigned local variable 'SR'".

What is the application?
Its just a code snippet. I'm busy learning C# & want to get the basics right.

In any enterprise situation, you shouldn't rely on being able to control GC.
I'm not. That is the problem. Apparently this is one of the areas not covered by GC, so it has to be done manually.

As for risk of data loss, I'd need to read up on it to understand.
First article quoted above, 90% down. ("Forcing an Object to Clean Up")

What if you put the streamwriter in a Using statement,that way you don't need to call the close function?
Clever. Plus one can still combine it to catch exceptions in case the new portion doesn't work (e.g. bad path).

Code:
            try
            {
                using (StreamWriter SR = new StreamWriter(@"C:\testout.txt"))
                {
                    SR.WriteLine(@"Testing");
                }
            }
            catch (Exception E)
            {
                Console.WriteLine(E.Message);
            }

Looks like that is the optimal way of doing it.

Thanks people
 
This is exactly what the using statement is for.
Code:
using (sr = new StreamWriter(....) ) 
{
   ....
   ....
   sr.close();
}
 
Apparently the using statement will call .Dispose on its own. Not sure how that differs from .Close but I'm guessing both will do the trick.
 
That was my initial reaction too because that is how its done in Delphi. Declare it outside & then open the file inside the try to catch exceptions. I can't see a way to split it that way in c# though.

Code:
            StreamWriter SR;
            try
            {
                SR = new StreamWriter(@"C:\testout.txt");
                SR.WriteLine(@"Testing");               
            }
            catch (Exception E)
            {
                Console.WriteLine(E.Message);
            }
            finally
            {
                SR.Close();
                Console.Read();
            }

Which gives me "Use of unassigned local variable 'SR'".

Thanks people
Code:
StreamWriter SR = null;
try {
...
...sorts your problem out there, by the way.

I'd recommend the using statement.
 
Apparently the using statement will call .Dispose on its own. Not sure how that differs from .Close but I'm guessing both will do the trick.

Quite true. In the MSIL a using statement actually turns into a try/finally statement, with the .Close() automatically called in the finally block. Awesome little helper, that. It's recommended that you don't call .Close() or .Dispose() manually if you are making use of a using {} block.
 
Apparently the using statement will call .Dispose on its own. Not sure how that differs from .Close but I'm guessing both will do the trick.

That's exactly what it does - try wrap a using statement around an object that does not implement the Dispose method..
 
Or without a using block to get rid of use of unassigned variable.

Code:
StreamWriter SR;
try
{
    SR = new StreamWriter(@"C:\testout.txt");
    SR.WriteLine(@"Testing");               
}
catch (Exception E)
{
    Console.WriteLine(E.Message);
}
finally
{
    if (SR != null)
    {
        SR.Close();
    }
    Console.Read();
}

But obviously using is better.
 
Call Dispose when you are finished using the TextWriter. The Dispose method leaves the TextWriter in an unusable state. After calling Dispose, you must release all references to the TextWriter so the garbage collector can reclaim the memory that the TextWriter was occupying.

Note: 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.

http://msdn.microsoft.com/en-us/library/ms227564.aspx
 
Top
Sign up to the MyBroadband newsletter
X