我有以下代码
public static byte[] Compress(byte[] CompressMe)
{
using (MemoryStream ms = new MemoryStream())
{
using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress,true))
{
gz.Write(CompressMe, 0, CompressMe.Length);
ms.Position = 0;
byte[] Result = new byte[ms.Length];
ms.Read(Result, 0, (int)ms.Length);
return Result;
}
}
}
这很好用,但是当我对它运行代码分析时,会出现以下消息
CA2202 : Microsoft.Usage : Object 'ms' can be disposed more than once in
method 'Compression.Compress(byte[])'. To avoid generating a
System.ObjectDisposedException you should not call Dispose more than one
time on an object.
就我而言,当GZipStream为Disposed时,由于构造函数的最后一个参数(leaveOpen = true),它会使底层Stream(ms)保持打开状态。
如果我稍微改变我的代码..删除MemoryStream周围的'using'块并将'leaveOpen'参数更改为false。
public static byte[] Compress(byte[] CompressMe)
{
MemoryStream ms = new MemoryStream();
using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress, false))
{
gz.Write(CompressMe, 0, CompressMe.Length);
ms.Position = 0;
byte[] Result = new byte[ms.Length];
ms.Read(Result, 0, (int)ms.Length);
return Result;
}
}
这就是......
CA2000 : Microsoft.Reliability : In method 'Compression.Compress(byte[])',
object 'ms' is not disposed along all exception paths. Call
System.IDisposable.Dispose on object 'ms' before all references to
it are out of scope.
我不能赢...(除非我遗漏了一些明显的东西)我已经尝试了各种各样的事情,比如试试/最终围绕块,并在那里处理MemoryStream,但它要么说我正在处理两次,或根本没有!
这有时是跑步的问题 CodeAnalysis,有时候你 根本无法取胜 你必须选择较小的邪恶。
在这种情况下,我认为正确的实现是第二个例子。为什么?根据 .NET Reflector, 实施 GZipStream.Dispose()
将处置 MemoryStream
对你而言 GZipStream 拥有 该 的MemoryStream。
相关部分 GZipStream
以下课程:
public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen)
{
this.deflateStream = new DeflateStream(stream, mode, leaveOpen, true);
}
protected override void Dispose(bool disposing)
{
try
{
if (disposing && (this.deflateStream != null))
{
this.deflateStream.Close();
}
this.deflateStream = null;
}
finally
{
base.Dispose(disposing);
}
}
由于您不希望完全禁用该规则,因此只能使用使用该方法来禁止此方法 CodeAnalysis.SupressMessage
属性。
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability ", "CA2000:?", Justification = "MemoryStream will be disposed by the GZipStream.")]
注意: 您将填写完整的规则名称(即 CA2000:?
)因为我不知道你发布的错误信息是什么。
HTH,
编辑:
@CodeInChaos:
深入了解实施情况 DeflateStream.Dispose
我相信它仍会为你处理MemoryStream而不管它调用的leaveOpen选项 base.Dispose()
。
编辑 忽略上面的内容 DeflateStream.Dispose
。我在Reflector中查看错误的实现。请参阅评论了解详情
除了处置问题,您的代码也被破坏了。您应该在回读数据之前关闭zip流。
还有一个 ToArray()
方法 MemoryStream
,不需要自己实现。
using (MemoryStream ms = new MemoryStream())
{
using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress,true))
{
gz.Write(CompressMe, 0, CompressMe.Length);
}
return ms.ToArray();
}
我只是压制警告,因为这是误报。代码分析可以为您服务,而不是相反。
从 这个页面在MSDN中
Stream stream = null;
try
{
stream = new FileStream("file.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(stream))
{
stream = null;
// Use the writer object...
}
}
finally
{
if(stream != null)
stream.Dispose();
}
这是尝试...最终在您的解决方案中缺少导致第二条消息。
如果这:
GZipStream gz = new GZipStream(ms, CompressionMode.Compress, false)
失败的流将不会被处置。
实际上,有效地在内存流上调用两次dispose不会导致任何问题,在MemoryStream类中进行编码并且在测试Microsoft看起来很容易。因此,如果您不想压制规则,另一种方法是将您的方法拆分为两个:
public static byte[] Compress(byte[] CompressMe)
{
using (MemoryStream ms = new MemoryStream())
{
return Compress(CompressMe, ms);
}
}
public static byte[] Compress(byte[] CompressMe, MemoryStream ms)
{
using (GZipStream gz = new GZipStream(ms, CompressionMode.Compress, true))
{
gz.Write(CompressMe, 0, CompressMe.Length);
ms.Position = 0;
byte[] Result = new byte[ms.Length];
ms.Read(Result, 0, (int)ms.Length);
return Result;
}
}
你必须去上学:
public static byte[] Compress(byte[] CompressMe)
{
MemoryStream ms = null;
GZipStream gz = null;
try
{
ms = new MemoryStream();
gz = new GZipStream(ms, CompressionMode.Compress, true);
gz.Write(CompressMe, 0, CompressMe.Length);
gz.Flush();
return ms.ToArray();
}
finally
{
if (gz != null)
{
gz.Dispose();
}
else if (ms != null)
{
ms.Dispose();
}
}
}
我知道看起来很可怕,但这是安抚警告的唯一方法。
就个人而言,我不喜欢编写这样的代码,所以只要基于Dispose调用应该是幂等的(并且在这种情况下)来抑制多个dispose警告(如果适用)。