我有很多像这样的代码:
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而且我不禁想到我做错了什么但是我没有看到它。 我做错了什么?
答案 0 :(得分:15)
叹息,不是很累。通过使用推荐的Create()方法避免所有这些:
using (var reader = XmlReader.Create(@"C:\Temp\SNB-RSS.xml")) {
//...
}
答案 1 :(得分: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。
答案 2 :(得分: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 */
}
}
我认为,是正确的,但仍会产生虚假警告。这闻起来就是一个很好的例子,它展示了静态分析工具的局限性。
正如其他人所说,还有另一个API可以直接从文件名(XmlReader.Create()
)创建阅读器,这可以避免所有这些(并显示精心设计的以场景为中心的API是一件令人惊讶的好事各种原因)。
答案 3 :(得分:1)
这是一个已知问题
如果您使用的是StreamWriter而不是XmlTextReader(如上面的解决方案中所示),您可以通过相关的构造函数使用类似的方法; e.g。
var sw = new StreamWriter("filename.txt");
或
var sw = new StreamWriter("filename.txt", /*append to file = */ false );
从文档中不清楚第一种形式的构造函数是否会覆盖或附加到文件。
答案 4 :(得分:0)
正如this回答中所提到的,正确解决它的唯一方法是执行as recommended in CA2202并使用外部try-finally块而不是外部使用块。在内部使用中,将外部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模式。但是对于嵌套使用的重复模式,我宁愿这样做,也不是每次重复完整的事情。
答案 5 :(得分:0)
只需使用&#39;使用&#39;对于文件流
using(FileStream fs = new FileStream(fileName, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// some codes here
}
不要修改fs,也不要在花括号里面使用fs.close()。
答案 6 :(得分:-1)
在FileStream本身上也使用using
语句,就像在XmlTextReader上一样。
http://msdn.microsoft.com/en-us/library/system.io.filestream(VS.71).aspx
Grz,Kris。