8

我有很多这样的代码:

FileStream fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open); 
using (XmlTextReader reader = new XmlTextReader(fs)) 
{ 
   /* Some other code */
}

这给了我以下代码分析警告:

CA2000 : Microsoft.Reliability : In method 'SF_Tester.Run()', object 'fs' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'fs' before all references to it are out of scope.

如果我遵循建议并将 File.Open 放在 using 语句中,我会得到:

CA2202 : Microsoft.Usage : Object 'fs' can be disposed more than once in method 'SF_Tester.Run()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 39

我正在使用 VS2010,我不禁认为我做错了什么,但我没有看到。我究竟做错了什么?

4

7 回答 7

15

咳咳,是不是很累。通过使用推荐的 Create() 方法来避免所有这些:

 using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
     //...
 }
于 2010-06-27T19:15:13.260 回答
11

由于没有人提供解决此问题的解决方案,我在这里写下我的工作解决方案:

FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite,    FileShare.ReadWrite);
try
{
   using (var fileWriter = new StreamWriter(fs, encoding))
   {
       fs = null;
       fileWriter.Write(content);
    }
 }
 finally
 {
     if (fs != null)
         fs.Dispose();
 }

这将删除 CA2000。

于 2010-09-13T12:41:31.137 回答
1

我只是猜测;现在没有时间进行全面分析。

假设XmlTextReader构造函数“获得”传入的流的所有权,因此XmlTextReader也将处理Dispose底层流。这可以解释你看到的行为。也许XmlTextReader构造函数可以抛出,在那种情况下,原来的警告是fs有意义的。但是,鉴于该假设,此代码

        var fs = File.Open(@"C:\Temp\SNB-RSS.xml", FileMode.Open);
        XmlTextReader reader = null;
        try
        {
            reader = new XmlTextReader(fs);
        }
        finally
        {
            if (reader== null)
            {
                fs.Dispose();
            }
        }
        if (reader != null)
        {
            using (reader)
            {
                /* Some other code */
            }
        }

我认为是正确的,但仍然会产生虚假的警告。这听起来像是一个很好的例子,展示了静态分析工具的局限性。

XmlReader.Create()正如其他人所说,还有另一个API可以直接从文件名(

于 2010-06-27T19:15:22.017 回答
1

这是一个已知问题

http://connect.microsoft.com/VisualStudio/feedback/details/535118/ca2000-and-ca2202-offer-contradictory-warnings

如果您使用的是 StreamWriter 而不是 XmlTextReader (如上面的解决方案),您可以通过相关的构造函数使用类似的方法;例如

var sw = new StreamWriter("filename.txt");

或者

var sw = new StreamWriter("filename.txt", /*append to file = */ false );

从文档中不清楚第一种形式的构造函数是否会覆盖或附加到文件。

于 2010-08-18T08:56:11.487 回答
0

答案所述,正确解决此问题的唯一方法是按照 CA2202 中的建议进行操作,并使用外部 try-finally 块而不是外部 using 块。在内部使用中,将外部 IDisposable 对象设置为 null 以防止在内部使用完成后对其进行访问。

这是一个“正确”执行的通用包装器,即围绕设计不良的 XmlReader 工作(也许它不应该拥有它接收到的流的所有权?不确定正确的方法是什么)

免责声明:未经测试

public static TResult SafeNestedUsing<TOuter, TInner, TResult>(Func<TOuter> createOuterDisposable, Func<TOuter, TInner> createInnerDisposable, Func<TInner, TResult> body)
        where TInner : IDisposable
        where TOuter : class, IDisposable
    {
        TOuter outer = null;
        try
        {
            outer = createOuterDisposable();
            using (var inner = createInnerDisposable(outer))
            {
                var result = body(inner);
                outer = null;
                return result;
            }
        }
        finally
        {
            if (null != outer)
            {
                outer.Dispose();
            }
        }
    }

示例用法:

SafeNestedUsing<MemoryStream, XmlReader, XmlDocument>(
    ()          => new MemoryStream(array),
    (memStream) => XmlReader.Create(memStream, xmlReaderSettings),
    (xmlReader) =>
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlReader);
        return xmlDoc;
    });

笨拙,您可能会争辩说最好重复 try/set null/finally 模式。但是对于嵌套使用的重复模式,我宁愿这样做而不是每次都重复完整的事情。

于 2013-01-03T01:05:18.993 回答
0

只需对文件流使用“使用”

 using(FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// some codes here

}

不要修改 fs 并且不要在使用花括号的内部使用 fs.close() 。

于 2014-12-01T14:00:17.400 回答
-1

using就像在 XmlTextReader 上一样,也可以在 FileStream 本身上使用该语句。

http://msdn.microsoft.com/en-us/library/system.io.filestream(VS.71).aspx

格兹,克里斯。

于 2010-06-27T18:58:55.420 回答