tes*_*ino 101 .net c# code-analysis fxcop
任何人都可以告诉我如何从以下代码中删除所有CA2202警告?
public static byte[] Encrypt(string data, byte[] key, byte[] iv)
{
using(MemoryStream memoryStream = new MemoryStream())
{
using (DESCryptoServiceProvider cryptograph = new DESCryptoServiceProvider())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
using(StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(data);
}
}
}
return memoryStream.ToArray();
}
}
Run Code Online (Sandbox Code Playgroud)
警告7 CA2202:Microsoft.Usage:对象'cryptoStream'可以在方法'CryptoServices.Encrypt(string,byte [],byte [])'中多次处理.为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose:Lines:34
警告8 CA2202:Microsoft.Usage:对象'memoryStream'可以在方法'CryptoServices.Encrypt(string,byte [],byte [])'中多次处理.为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose:Lines:34,37
您需要Visual Studio代码分析才能看到这些警告(这些不是c#编译器警告).
Jor*_*dão 139
在这种情况下,您应该取消警告.处理一次性用品的代码应该是一致的,您不应该关心其他类别对您创建的一次性用品的所有权并且也要求Dispose它们.
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] Encrypt(string data, byte[] key, byte[] iv) {
using (var memoryStream = new MemoryStream()) {
using (var cryptograph = new DESCryptoServiceProvider())
using (var cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
using (var streamWriter = new StreamWriter(cryptoStream)) {
streamWriter.Write(data);
}
return memoryStream.ToArray();
}
}
Run Code Online (Sandbox Code Playgroud)
更新:在IDisposable.Dispose文档中,您可以阅读:
如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用.如果多次调用Dispose方法,则该对象不得抛出异常.
可以说这个规则的存在是为了让开发人员能够using在一系列一次性用品中巧妙地使用这个陈述,就像我上面所示(或者这可能只是一个很好的副作用).出于同样的原因,CA2202没有任何用处,应该在项目方面进行抑制.真正的罪魁祸首是错误的实施Dispose,CA1065应该照顾(如果它是你的责任).
Han*_*ant 41
嗯,这是准确的,这些流上的Dispose()方法将被多次调用.StreamReader类将获取cryptoStream的"所有权",因此处理streamWriter也将处理cryptoStream.类似地,CryptoStream类接管memoryStream的责任.
这些并不是真正的错误,这些.NET类对多个Dispose()调用具有弹性.但是如果你想摆脱警告,那么你应该删除这些对象的using语句.如果代码抛出异常,在推理会发生什么时会让自己痛苦一点.或者使用属性关闭警告.或者只是忽略警告,因为它很愚蠢.
当处理StreamWriter时,它将自动处理包装的Stream(此处:CryptoStream).CryptoStream还会自动处理包装的Stream(此处为:MemoryStream).
因此,您的MemoryStream由CryptoStream和using语句处理.并且您的CryptoStream由StreamWriter和外部using语句处理.
经过一些实验,似乎不可能完全摆脱警告.理论上,MemoryStream需要处理,但理论上你不能再访问它的ToArray方法了.实际上,不需要处理MemoryStream,因此我将使用此解决方案并抑制CA2000警告.
var memoryStream = new MemoryStream();
using (var cryptograph = new DESCryptoServiceProvider())
using (var writer = new StreamWriter(new CryptoStream(memoryStream, ...)))
{
writer.Write(data);
}
return memoryStream.ToArray();
Run Code Online (Sandbox Code Playgroud)
我会这样做#pragma warning disable.
.NET Framework指南建议以可以多次调用的方式实现IDisposable.Dispose.来自IDisposable.Dispose的MSDN描述:
如果多次调用Dispose方法,则该对象不得抛出异常
因此警告似乎几乎毫无意义:
为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose
我想可以认为,如果您使用的是严格执行的IDisposable对象,并且不符合标准实施指南,则警告可能会有所帮助.但是当你使用.NET Framework中的类时,我会说使用#pragma来抑制警告是安全的.恕我直言,这比在这个警告的MSDN文档中建议的箍更可取.
Hen*_*rik -4
编译时不会发出警告:
public static byte[] Encrypt(string data, byte[] key, byte[] iv)
{
MemoryStream memoryStream = null;
DESCryptoServiceProvider cryptograph = null;
CryptoStream cryptoStream = null;
StreamWriter streamWriter = null;
try
{
memoryStream = new MemoryStream();
cryptograph = new DESCryptoServiceProvider();
cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write);
var result = memoryStream;
memoryStream = null;
streamWriter = new StreamWriter(cryptoStream);
cryptoStream = null;
streamWriter.Write(data);
return result.ToArray();
}
finally
{
if (memoryStream != null)
memoryStream.Dispose();
if (cryptograph != null)
cryptograph.Dispose();
if (cryptoStream != null)
cryptoStream.Dispose();
if (streamWriter != null)
streamWriter.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
编辑回应评论:我刚刚再次验证此代码不会生成警告,而原始代码会生成警告。在原始代码中,CryptoStream.Dispose()和MemoryStream().Dispose() 实际上被调用了两次(这可能是问题,也可能不是问题)。
修改后的代码工作原理如下:null一旦处置责任转移到另一个对象,引用就会设置为 。例如,在调用构造函数成功后memoryStream设置为。调用构造函数成功后设置为。如果没有发生异常,会在块中被释放,并且会依次释放和。nullCryptoStreamcryptoStreamnullStreamWriterstreamWriterfinallyCryptoStreamMemoryStream