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?
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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With