39

新的 Visual Studio 2012 抱怨我一直使用的常见代码组合。我知道这似乎有点矫枉过正,但我​​在我的代码中做了以下“只是为了确定”。

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

Visual Studio 正在“警告”我,我不止一次处理 fs。所以我的问题是,写这个的正确方法是:

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

或者我应该这样做(或其他未提及的变体)。

var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

using (var sr = new StreamReader(fs))
{
    // Code here
}

我在 StackOverflow 中搜索了几个问题,但没有找到直接解决此组合最佳实践的内容。

谢谢!

4

7 回答 7

41

以下是微软推荐的做法。它又长又笨重,但很安全:

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();
}

此方法将始终确保处理应该处理的所有内容,尽管可能会引发什么异常。例如,如果StreamReader构造函数抛出异常,FileStream仍然会被正确处理。

于 2012-08-17T05:29:46.723 回答
16

Visual Studio 正在“警告”我,我不止一次处理 fs。

你是,但这很好。IDisposable.Dispose的文档内容如下:

如果多次调用对象的Dispose方法,则对象必须忽略第一次调用之后的所有调用。如果多次调用其Dispose方法,则该对象不得引发异常。

基于此,警告是虚假的,我的选择是保留代码原样,并禁止警告。

于 2012-08-18T20:37:46.737 回答
6

由于 Dan 的答案似乎只适用于 StreamWriter,我相信这可能是最可接受的答案。(Dan 的回答仍然会使用 StreamReader 给出两次已处理的警告 - 正如 Daniel Hilgarth 和 exaceratedexpert 所提到的,StreamReader 会处理文件流)

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

这与 Daniel Hilgarth 的回答非常相似,修改为通过 StreamReader 上的 Using 语句调用 dispose,因为现在很清楚 StreamReader 将在 FileStream 上调用 dispose (根据所有其他帖子,参考的文档)

更新:

我找到了这篇文章。为了它的价值。 处理流阅读器会关闭流吗?

于 2012-08-17T18:24:34.393 回答
2

是的,正确的方法是使用您的第一个替代方法:

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

原因如下:
处理StreamReaderonly 会处理 the ,FileStream所以这实际上是您需要处理的唯一事情。

您的第二个选项(只是内部“使用”)不是解决方案,因为FileStream如果StreamReader.

于 2012-08-17T05:17:19.267 回答
1

这是因为您使用的方式在StreamReader处理流时会对其进行处理。所以,如果你也处理流,它会被处理两次。有些人认为这是一个缺陷——StreamReader但它仍然存在。在 VS 2012 (.NET 4.5) 中,可以选择StreamReader不处理流,使用新的构造函数:http: //msdn.microsoft.com/en-us/library/gg712952

于 2012-08-17T16:06:56.997 回答
1

两种解决方案:

A ) 您信任 Reflector 或 Documentation,并且您知道*Reader并将*Writer关闭底层证券*Stream。但是警告:如果抛出异常,它将不起作用。所以这不是推荐的方式:

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

B)您忽略了文档状态的警告The object must not throw an exception if its Dispose method is called multiple times.这是推荐的方法,因为它是始终使用的好习惯using,并且在抛出异常的情况下是安全的:

[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
    }
}
于 2014-04-18T16:52:36.827 回答
0

考虑到这个(完全合法的!)问题产生的所有废话,这将是我的偏好:

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();
}

下面的链接说明了完全合法的语法。IMO,这种“使用”语法比嵌套的“使用”要好得多。但我承认 - 它不能解决原来的问题:

恕我直言...

于 2012-08-17T19:08:33.890 回答