【问题标题】:Satisfying Code Analysing disposal rule with MemoryStream and CryptoStream [duplicate]使用 MemoryStream 和 CryptoStream 满足代码分析处置规则 [重复]
【发布时间】:2014-12-16 20:58:37
【问题描述】:

我在满足用于处置 MemoryStream 对象的代码分析规则时遇到问题。

这是我现在的代码:

byte[] bytes;
MemoryStream stream = new MemoryStream();

using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
    cs.Write(buffer, 0, buffer.Length);
}

bytes = stream.ToArray();
stream.Close();

return bytes;

这会导致警告说流可能被释放两次,或者可能被释放(每个警告一个)。

我也尝试将其包装到 using(MemoryStream stream = new MemoryStream()) 块中。这会导致前一个警告。

最后,删除对Close()Dispose() 的调用会导致后一个警告。

有没有办法同时满足这两个条件?我认为问题是可能会关闭它的异常路径,但我对这些类的工作方式不是很熟悉。

【问题讨论】:

    标签: c# memory dispose


    【解决方案1】:

    你可以通过使用丢弃所有的流

    var bytes = transform.TransformFinalBlock(buffer, 0, buffer.Length);
    

    如果没有流,则无需担心处理它们;)

    【讨论】:

    【解决方案2】:

    如果它触发,我个人倾向于在我的源代码中禁止该规则,因为大多数对象都没有被处理两次的问题。但是,如果您想在不压制的情况下满足规则,则需要这样做:

            byte[] bytes = new byte[1024];
            byte[] buffer = new byte[1024];
            ICryptoTransform transform = null;
    
            MemoryStream stream = null;
    
            try
            {
                stream = new MemoryStream();
                MemoryStream tempStream = stream
    
                using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
                {
                    // set stream to null immediately so it doesn't get disposed by finally
                    stream = null;
    
                    cs.Write(buffer, 0, buffer.Length);
                    bytes = tempStream.ToArray();
                }
            }
            finally
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }
    
            return bytes;
    

    【讨论】:

    • 您的代码导致 CA2202 不要多次处理对象..
    • 不错不错。我将 steam = null 语句移到 using 语句中的第一行代码,FXCop 很高兴。我仍然不喜欢这条规则。
    • 没有警告,但是你现在在设置stream = null后访问stream.ToArray()
    • 是的,更新的答案满足 FXCop 规则并且不使用 Null 对象
    • 我明白你为什么现在就取消规则了 :)
    【解决方案3】:

    CryptoStream 被释放时(当using 块结束时),它在MemoryStream 上调用Close,后者又调用Dispose

    因此,您无需亲自致电Dispose(通过using)或Close。这样,stream 只会被处理一次。

    MemoryStream stream = new MemoryStream();
    using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
    {
        cs.Write(buffer, 0, buffer.Length);
        return stream.ToArray();            
    }
    

    【讨论】:

    • 如果 CryptoStream 构造函数抛出,该代码可能会使 MemoryStream 未处理。
    • 没错,但这并不是(IMO)大问题。一个空的 MemoryStream 不大,最终还是会被 GC 处理。希望 CryptoStream 的 ctor 不太可能抛出。如果不触发代码分析警告之一,我看不到解决方法。
    • 我倾向于禁止这条规则并使用 2 using 语句。但是,如果您不想压制并始终处置,我会使用 try/finally 块更新我的答案以满足规则。
    • @Blorgbeard MemoryStream 设计为无操作 Dispose,因为它必须保持内部缓冲区(托管字节数组)处于活动状态以供以后调用 ToArray。所以即使不处理“巨大的MemoryStream”也不是问题(很高兴有正确的代码,但没有真正的区别)。
    猜你喜欢
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多