防止多次处置对象

时间:2013-03-13 13:44:58

标签: c# .net stream dispose msdn

请考虑以下代码:

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        // Use the writer object...
    }
}

writer流被处置时,它会在内部处理FileStream stream

除了MSDN recommendation以外,还有其他设计可以在finally子句中处理外部使用的流:

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

2 个答案:

答案 0 :(得分:3)

此特定情况的解决方案是致电the overload of the StreamWriter constructor that lets you tell it not to dispose the underlying stream

不幸的是,这仅适用于.Net 4.5;否则你将不得不做你正在做的事情。

另外,请参阅此主题:Is there any way to close a StreamWriter without closing its BaseStream?

顺便提一下,OP中的代码 NOT 会在我尝试时导致异常!

以下示例假设存在名为“C:\ TEST”的文件夹:

using System;
using System.IO;

namespace Demo
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            // This does NOT cause any exceptions:

            using (Stream stream = new FileStream("c:\\test\\file.txt", FileMode.OpenOrCreate))
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.Write("TEST");
                }
            }
        }
    }
}

答案 1 :(得分:3)

这种情况下,FxCop与.NET Framework中的设计选择存在很大差异。 StreamWriter假设流的所有权引起问题。这通常是“成功的陷阱”设计选择,大多数程序员都会认为关闭StreamWriter足以让流处理掉。特别是当他们使用Close()而不是Dispose()时。

在绝大多数情况下都适用。大多数情况下,一个特殊用途是非常有问题的是CryptoStream。在CryptoStream被刷新和处理之前关闭基础流时需要刷新和不可诊断故障的类。 FxCop警告适当的情况,尽管它太容易辨认特定问题太过神秘;)

一般情况下,程序员编写了自己的Dispose()方法,并且忘记了多次调用它的安全性。这就是FxCop警告引起注意的原因,它不够聪明,无法看到Dispose方法实际上是安全的。

在这种特定情况下,FxCop警告是无用的。所有.NET Framework提供的Dispose()方法实现都是安全的。 FxCop应该自动禁止.NET框架代码的这种警告。但不是,微软也使用它。 .NET框架源代码中有[strong>很多 [SuppressMessage]属性。

解决警告太丑陋且容易出错。没有意义,因为没有什么事实出错。请记住,FxCop只是一个诊断工具,旨在生成“您已考虑”消息。当你忽视规则时,警察警察不会把你关进监狱。这是编译器的工作。

使用[SuppressMessage]属性关闭警告。