Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# StreamReader in a try/finally

Tags:

c#

.net

I have a question today involving the StreamReader class. Specifically initializing this class using the filename parameter for example:

TextReader tr = new StreamReader(fileName);

Obviously when this action is finished, its important to close the stream like this:

 tr.Close();

I would like to have this in a try / finally, the problem is I can't find a way to do this. Here are some variations I have found that DO NOT work:

    try
        {
            var serializer = new XmlSerializer(type);
            TextReader tr = new StreamReader(fileName);
            var obj = serializer.Deserialize(tr);
        }
    finally
        {
            tr.Close();    
        }

and worse:

     TextReader tr;  
        try
        {
            var serializer = new XmlSerializer(type);
            tr = new StreamReader(fileName);
            var obj = serializer.Deserialize(tr);
        }
        finally
        {
            tr.Close();    
        }

So is it possible to have a StreamReader close in a finally?

like image 864
JL. Avatar asked Jan 30 '10 00:01

JL.


2 Answers

The easiest way is to use a using statement:

using (TextReader tr = new StreamReader(fileName))
{
  // ...
}

The compiler will generate a try-finally block for you and put code to call Close (actually Dispose) in the finally.

If you need to spell out the finally explicitly, your second example will work, except that you need to force tr to be initialised:

TextReader tr = null;

And you will of course want to check for tr != null inside your finally block, in case an exception happened before tr = new StreamReader(...) was executed.

like image 72
itowlson Avatar answered Oct 27 '22 14:10

itowlson


Yes, either:

TextReader tr = null;
try
{
    var serializer = new XmlSerializer(type);
    tr = new StreamReader(fileName);
    var obj = serializer.Deserialize(tr);
}
finally
{
    if (tr != null)
        tr.Close();    
}

or just:

using (TextReader tr = new StreamReader(fileName))
{
    var serializer = new XmlSerializer(type);
    var obj = serializer.Deserialize(tr);
}

The reason the first piece of code in your question did not compile was that the tr variable was declared inside the try-block, which made it inaccessible to the finally-block.

The reason the second piece of code in your question did not compile was that the tr variable was not given a value, and if the new XmlSerializer were to throw an exception, it wouldn't get one in the try-block either, which means you have a possible undefined value in the variable when it reaches the finally-block.

The solution, if you want to absolutely keep a try/finally structure, is to ensure the variable has an initial value, and only call .Close if it has changed.

Of course, the most correct way is to use a using block, which takes care of all the details for you. Note that this will change the order of construction between the reader and the serializer object, or you can have the code like this, which preserves the order you had in your question (it won't matter in this case though):

var serializer = new XmlSerializer(type);
using (TextReader tr = new StreamReader(fileName))
{
    var obj = serializer.Deserialize(tr);
}
like image 42
Lasse V. Karlsen Avatar answered Oct 27 '22 14:10

Lasse V. Karlsen