Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CA2202,如何解决这个案子_C#_.net_Code Analysis_Fxcop - Fatal编程技术网

C# 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())

有人能告诉我如何从下面的代码中删除所有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();
    }
}
警告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