using statement FileStream and / or StreamReader - Visual Studio 2012 Warnings

别来无恙 提交于 2019-11-27 07:46:08

The following is how Microsoft recommends doing it. It is long and bulky, but safe:

FileStream fs = null;
try
{
    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using (TextReader tr= new StreamReader(fs))
    {
        fs = null;
        // Code here
    }
}
finally
{
    if (fs != null)
        fs.Dispose();
}

This method will always ensure that everything is disposed that should be despite what exceptions may be thrown. For example, if the StreamReader constructor throws an exception, the FileStream would still be properly disposed.

Visual studio is 'warning' me that I am disposing of fs more than once.

You are, but that is fine. The documentation for IDisposable.Dispose reads:

If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times.

Based on that, the warning is bogus, and my choice would be to leave the code as it is, and suppress the warning.

JHubbard80

As Dan's answer only appears to work with StreamWriter, I believe this might be the most acceptable answer. (Dan's answer will still give the disposed twice warning with StreamReader - as Daniel Hilgarth and exacerbatedexpert mentions, StreamReader disposes the filestream)

using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
    string line;
    while ((line = tr.ReadLine()) != null)
    {
        // Do work here
    }
}

This is very similar to Daniel Hilgarth's answer, modified to call dispose via the Using statement on StreamReader as it is now clear StreamReader will call dispose on FileStream (According to all the other posts, documentation referenced)

Update:

I found this post. For what it is worth. Does disposing streamreader close the stream?

Daniel Hilgarth

Yes, the correct way would be to use your first alternative:

using (FileStream fs = new FileStream(filePath, FileMode.Open,
                                      FileAccess.Read, FileShare.ReadWrite)) 
{ 
    TextReader tr = new StreamReader(fs); 
    // do stuff here 
} 

The reason is the following:
Disposing the StreamReader only disposes the FileStream so that's actually the only thing you need to dispose.

Your second option (just the inner "using") is no solution as it would leave the FileStream undisposed if there was an exception inside the constructor of the StreamReader.

It's because the way you used StreamReader disposes the stream when it is disposed. So, if you dispose the stream too, it's being disposed twice. Some consider this a flaw in StreamReader--but it's there none-the-less. In VS 2012 (.NET 4.5) there is an option in StreamReader to not dispose of the stream, with a new constructor: http://msdn.microsoft.com/en-us/library/gg712952

Two solutions:

A) You trust Reflector or Documentation and you know *Reader and *Writer will close the underlying *Stream. But warning: it won't work in case of a thrown Exception. So it is not the recommended way:

using (TextReader tr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
    // Code here
}

B) You ignore the warning as documentation states The object must not throw an exception if its Dispose method is called multiple times. It's the recommended way, as it's both a good practice to always use using, and safe in case of a thrown Exception:

[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal void myMethod()
{
    [...]
    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (TextReader tr = new StreamReader(fs))
    {
        // Code here
    }
}
paulsm4

Given all the nonsense this (perfectly legitimate!) question generated, this would be my preference:

FileStream fs = null;
TextReader tr= null;
try
{
    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    tr= new StreamReader(fs);
    // Code here
}
finally
{
    if (tr != null)
        tr.Dispose();
    if (fs != null)
        fs.Dispose();
}

The links below illustrate perfectly legal syntax. IMO, this "using" syntax is far preferable to nested "using". But I admit - it does not solve the original question:

IMHO...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!