我试图确保我的编码遵循对象的正确处理,所以我将这些规则作为错误来执行。但是我在使用这段代码时遇到了问题。
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
class MyClass
{
public String ToXml()
{
var objSerializer =
new DataContractSerializer(GetType());
var objStream = new MemoryStream();
StreamReader objReader;
String strResult;
try
{
// Serialize the object
objSerializer.WriteObject(objStream, this);
// Move to start of stream to read out contents
objStream.Seek(0, SeekOrigin.Begin);
objReader = new StreamReader(objStream);
try
{
// Read Contents into a string
strResult = objReader.ReadToEnd();
}
finally
{
objReader.Dispose();
}
}
finally
{
if (objStream != null)
{
// objStream.Dispose();
}
}
return strResult;
}
}如果我注释掉了objStream.Dispose(),我会得到CA2000,因为我没有处理这个对象,但是如果我删除了注释,它就会说我正在处理不止一次。
还有什么在处理这个对象呢?或者我只是在处理多个流时做错了?
发布于 2014-02-20 16:49:30
这种情况现在也一直困扰着我。每隔几年,我就决定通过运行fxcop或Visual Studio中现在内置的代码分析来更新自己的代码分析“规则”。
我最初写了这段代码,认为我是一个好公民,因为我正确地使用了usings来处理:
using (MemoryStream msDecrypt = new MemoryStream())
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
}
decrypted = msDecrypt.ToArray();
}这段代码会导致CA2202 "Do not dispose objects multiple times“,这条规则最大的讽刺之处在于,它实际上并不是关于你的代码的问题,而是保护你在其他代码中的问题。微软一直有大量关于如何实现Dispose模式(http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx )的文档。但是,通过查看此代码分析规则(http://msdn.microsoft.com/en-us/library/ms182334.aspx)的详细信息,它揭示了此规则的用途
“正确实现的Dispose方法可以多次调用,而不会引发异常。但是,这是不能保证的,为了避免生成System.ObjectDisposedException,您不应该对对象多次调用Dispose。”
简而言之,这条规则就是为了保护自己不受那些不遵守规则的人的伤害。
很自然地,我修改了代码,使其看起来像这样:
MemoryStream msDecrypt = new MemoryStream()
//using (MemoryStream msDecrypt = new MemoryStream())
//{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
}
decrypted = msDecrypt.ToArray();
//}现在这个堆栈溢出帖子上的每个人都痛苦地意识到了新的问题,我们的朋友CA2000“在失去作用域之前处置对象” ...因此,在这一点上,我只是掌心了一分钟。我在谷歌上搜索了一下,找到了这篇文章。这时我意识到,要通过这两个CA规则,您需要确保所有代码分支都只处理一次。所以我开始做这件事,一旦你意识到这是你需要做的,这并不是一个困难的问题。
自然而然,代码演变成这样:
MemoryStream msDecrypt = null;
CryptoStream csDecrypt = null;
try
{
msDecrypt = new MemoryStream();
csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
csDecrypt.FlushFinalBlock();
decrypted = msDecrypt.ToArray();
}
finally
{
if (csDecrypt != null)
{
csDecrypt.Dispose();
}
else if (msDecrypt != null)
{
msDecrypt.Dispose();
}
}最后,我的代码没有产生CA2000或CA2202。这个故事的寓意是,由于代码分析规则已经以这种方式发展,USING语句的价值比过去少了很多。
有几种不同的方法可以编写代码来实现这一点,我只是选择了一种不会将显式调用与使用语句混合在一起的方法,因为我相信这样会更容易阅读,并且以一种结构上的方式来防止某人只是去包装另一个使用它,从而在不知不觉中导致了最初的问题。
发布于 2012-04-13 19:17:28
如果您释放了StreamReader,那么您也就释放了基础流。
如果您注释掉了objStream.Dispose(),那么您甚至可能会在到达嵌套的try块之前遇到抛出异常的情况-这将导致您的流得不到处理。
发布于 2012-04-13 19:20:27
这不是答案,但您可能会发现下面的代码更具可读性:
public String ToXml()
{
var objSerializer =
new DataContractSerializer(GetType());
using (var objStream = new MemoryStream())
{
// Serialize the object
objSerializer.WriteObject(objStream, this);
// Move to start of stream to read
// out contents
objStream.Seek(0, SeekOrigin.Begin);
using (var objReader =
new StreamReader(objStream))
{
// Read Contents into a string
retirm objReader.ReadToEnd();
}
}
}https://stackoverflow.com/questions/10139718
复制相似问题