C# CA2202,如何解决这个案子
有人能告诉我如何从下面的代码中删除所有CA2202警告吗C# CA2202,如何解决这个案子,c#,.net,code-analysis,fxcop,C#,.net,Code Analysis,Fxcop,有人能告诉我如何从下面的代码中删除所有CA2202警告吗 public static byte[] Encrypt(string data, byte[] key, byte[] iv) { using(MemoryStream memoryStream = new MemoryStream()) { using (DESCryptoServiceProvider cryptograph = new DESCryptoServiceProvider())
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();
}
}
警告7 CA2202:Microsoft。用法:对象“cryptoStream”可以在方法“CryptoServices.Encrypt(字符串,字节[],字节[])”中多次释放。为了避免生成System.ObjectDisposedException,您不应该对一个对象多次调用Dispose。:Lines:34
警告8 CA2202:Microsoft。用法:对象“memoryStream”可以在方法“CryptoServices.Encrypt(字符串,字节[],字节[])”中多次释放。为了避免生成System.ObjectDisposedException,您不应该对一个对象多次调用Dispose。:第34行,第37行
您需要Visual Studio代码分析来查看这些警告(这些不是c#编译器警告)。加密流基于memorystream
似乎正在发生的是,当crypostream被释放时(在使用结束时),memorystream也被释放,然后memorystream再次被释放。主题之外,但我建议您使用不同的格式化技术来分组
,使用
s:
using (var memoryStream = new MemoryStream())
{
using (var cryptograph = new DESCryptoServiceProvider())
using (var encryptor = cryptograph.CreateEncryptor(key, iv))
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
using (var streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(data);
}
return memoryStream.ToArray();
}
我还主张在这里使用var
s,以避免重复非常长的类名
另外,感谢@ShellShock指出,我不能省略第一次使用时使用的大括号,因为它会使中的memoryStream
返回语句超出范围。当a被处理时,它会自动处理已包装的(此处:the)。还将自动处理已包装的(此处为:的)
因此,您的代码将由和using语句处理。并且您的数据由和外部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();
准确地说,这些流上的Dispose()方法将被多次调用。StreamReader类将获得加密流的“所有权”,因此处理streamWriter也将处理加密流。类似地,CryptoStream类接管memoryStream的责任
这些并不是真正的bug,这些.NET类对多个Dispose()调用具有弹性。但是如果您想消除警告,那么应该删除这些对象的using语句。在推理如果代码抛出异常会发生什么时,你自己也会有点痛苦。或者用属性关闭警告。或者忽略这个警告,因为它很愚蠢。我使用了这种代码,它接受字节[]并返回字节[],而不使用流
public static byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
DES des = new DES();
des.BlockSize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.Zeros;
des.IV = IV
des.Key = key
ICryptoTransform encryptor = des.CreateEncryptor();
//and finaly operations on bytes[] insted of streams
return encryptor.TransformFinalBlock(plaintextarray,0,plaintextarray.Length);
}
通过这种方式,您所要做的就是使用编码将字符串转换为字节[]。我会使用#pragma warning disable
来实现这一点
NET Framework指导原则建议实现IDisposable.Dispose,使其可以多次调用。发件人:
如果多次调用该对象的Dispose方法,则该对象不得引发异常
因此,这一警告似乎毫无意义:
为了避免生成System.ObjectDisposedException,您不应该对对象多次调用Dispose
我想,如果您使用的IDisposable对象没有遵循标准的实现指南,那么这个警告可能会有所帮助。但是当像您这样使用.NET Framework中的类时,我认为使用#pragma来抑制警告是安全的。我认为这比像这样经历更可取。在这种情况下,您应该抑制警告。处理一次性用品的代码应该是一致的,并且您不必关心其他类是否拥有您创建的一次性用品的所有权,也不必对它们调用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();
}
}
更新:在文档中,您可以阅读以下内容:
如果对象的Dispose方法被多次调用,则该对象必须忽略第一次调用之后的所有调用。如果多次调用该对象的Dispose方法,则该对象不得引发异常
可以说,这条规则的存在是为了让开发人员能够像我上面所展示的那样,在一系列可处置的东西中合理地使用using
语句(或者这只是一个很好的副作用)。出于同样的原因,CA2202也没有什么用处,应该在项目方面加以抑制。真正的罪魁祸首可能是Dispose
的错误实现,并且应该注意这一点(如果这是您的责任)。这在没有警告的情况下编译:
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();
}
}
编辑以回应评论:
我刚刚再次验证了此代码没有生成警告,而原始代码生成警告。
在原始代码中,CryptoStream.Dispose()
和MemoryStream().Dispose(
)实际上被调用了两次(这可能是问题,也可能不是问题)
修改后的代码的工作原理如下:只要处置责任转移到另一个对象,引用就被设置为null
。例如,memoryStream
在调用CryptoStream
构造函数成功后设置为null
<调用StreamWriter
构造函数成功后,code>cryptoStream
设置为null
。如果没有出现异常,streamWriter
将在finally
块中处理,并依次处理CryptoStream
和MemoryStream
我在代码中遇到了类似的问题
看起来整个CA2202事件都被触发了,因为如果构造函数(CA2000)中发生异常,可以处理MemoryStream
这可以这样解决:
1 public static byte[] Encrypt(string data, byte[] key, byte[] iv)
2 {
3 MemoryStream memoryStream = GetMemoryStream();
4 using (DESCryptoServiceProvider cryptograph = new DESCryptoServiceProvider())
5 {
6 CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write);
7 using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
8 {
9 streamWriter.Write(data);
10 return memoryStream.ToArray();
11 }
12 }
13 }
14
15 /// <summary>
16 /// Gets the memory stream.
17 /// </summary>
18 /// <returns>A new memory stream</returns>
19 private static MemoryStream GetMemoryStream()
20 {
21 MemoryStream stream;
22 MemoryStream tempStream = null;
23 try
24 {
25 tempStream = new MemoryStream();
26
27 stream = tempStream;
28 tempStream = null;
29 }
30 finally
31 {
32 if (tempStream != null)
33 tempStream.Dispose();
34 }
35 return stream;
36 }
你会得到同样的结果。避免所有的使用和使用
/// <summary>
/// Gets a memory stream.
/// </summary>
/// <returns>A new memory stream</returns>
private static MemoryStream GetMemoryStream()
{
return new MemoryStream();
}
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);
streamWriter = new StreamWriter(cryptoStream);
streamWriter.Write(data);
return memoryStream.ToArray();
}
finally
{
if(streamWriter != null)
streamWriter.Dispose();
else if(cryptoStream != null)
cryptoStream.Dispose();
else if(memoryStream != null)
memoryStream.Dispose();
if (cryptograph != null)
cryptograph.Dispose();
}
}
public class SomeEncryption : IDisposable
{
private MemoryStream memoryStream;
private CryptoStream cryptoStream;
public static byte[] Encrypt(string data, byte[] key, byte[] iv)
{
// Do something
this.memoryStream = new MemoryStream();
this.cryptoStream = new CryptoStream(this.memoryStream, encryptor, CryptoStreamMode.Write);
using (var streamWriter = new StreamWriter(this.cryptoStream))
{
streamWriter.Write(plaintext);
}
return memoryStream.ToArray();
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (this.memoryStream != null)
{
this.memoryStream.Dispose();
}
if (this.cryptoStream != null)
{
this.cryptoStream.Dispose();
}
}
}
}
memoryStream = new MemoryStream()
cryptograph = new DESCryptoServiceProvider()
cryptoStream = new CryptoStream()
streamWriter = new StreamWriter()
memoryStream.Dispose(); //implicitly owned by cryptoStream
cryptoStream.Dispose(); //implicitly owned by streamWriter
streamWriter.Dispose(); //through a using
cryptoStream.Dispose(); //INVALID: second dispose through using
cryptograph.Dispose(); //through a using
memorySTream.Dipose(); //INVALID: second dispose through a using
return memoryStream.ToArray(); //INVALID: accessing disposed memoryStream