CA2202,如何解决这个问题?

101

请问有谁能告诉我如何从以下代码中删除所有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.Usage : 在方法'CrytpoServices.Encrypt(string, byte[], byte[])'中,对象'cryptoStream'可以被释放多次。为避免引发'System.ObjectDisposedException'异常,您不应该在一个对象上调用Dispose超过一次: 行数:34

警告 8 CA2202 : Microsoft.Usage : 在方法'CrytpoServices.Encrypt(string, byte[], byte[])'中,对象'memoryStream'可以被释放多次。为避免引发'System.ObjectDisposedException'异常,您不应该在一个对象上调用Dispose超过一次: 行数:34,37

要查看这些警告,您需要使用Visual Studio代码分析(这些不是C#编译器警告)。


1
此代码不会产生这些警告。 - Julien Hoarau
1
我在这个项目中没有收到任何警告(Warn level 4,VS2010)。如果有人在这个领域搜索问题,请附上警告文本。 - H H
29
"CAxxxx" 警告是由 "Code Analysis" 和 FxCop 生成的。 - dtb
这个警告不适用于所示代码 - 警告可以被抑制,以适应这种情况。一旦您审查了您的代码并同意该评估,请在您的方法上方放置此内容:"[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]" - 确保您的using块中有一个 "using System.Diagnostics.CodeAnalysis;" 语句。 - BrainSlugs83
12个回答

-1
我使用了这种代码,它接受 byte[] 并返回 byte[],而不使用流。
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);
}

这样,您所要做的就是使用编码将字符串转换为byte[]。


-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();
        }
    }

编辑回应评论:

我再次验证了一下,这段代码不会生成警告,而原始代码会。

在原始代码中,CryptoStream.Dispose()MemoryStream().Dispose()实际上被调用了两次(这可能是一个问题,也可能不是)。

修改后的代码工作方式如下:一旦负责释放的对象转移到另一个对象,引用就被设置为null。例如,在调用CryptoStream构造函数成功后,memoryStream被设置为nullStreamWriter构造函数成功后,cryptoStream被设置为null。如果没有异常发生,streamWriter将在finally块中被处理,并依次处理CryptoStreamMemoryStream


86
为了遵从一个本应该被抑制的警告信息,而刻意编写难看的代码是非常糟糕的行为。 - Jordão
4
我同意你不应该为一些可能在未来被修复的问题而毁坏你的代码,只需要压制它即可。 - peteski
3
这怎么解决问题?由于在 finally 块中 MemoryStream 仍可被释放两次,因此仍会报告 CA2202。 - Chris Gessler
3
由于CryptoStream在内部调用了MemoryStream的Dispose方法,可能会导致Dispose方法被调用两次,这就是警告出现的原因。我尝试了你的解决方案,但仍然收到了警告。 - Chris Gessler
2
哦,天啊,你是正确的——我没想到清理逻辑会和你的……逻辑-逻辑混在一起……这太奇怪和神秘了——当然,这很聪明——但再次强调,这很可怕——请不要在生产代码中这样做;明确一下:你知道这并没有解决任何实际的功能问题,对吧?(多次处理这些对象是可以的。)——如果可以的话,我会取消我的负评(SO阻止我这样做,它说你必须编辑答案)——但我只会勉强这样做……而且,认真地说,永远不要这样做。 - BrainSlugs83
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接