I have the following code
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;
}
}
}
This works fine, but when I run code analysis on it, it comes up with the following message
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.
As far as I’m concerned, when the GZipStream is Disposed, it leaves the underlying Stream (ms) open, due to the last parameter of the constructor (leaveOpen=true).
If I change my code slightly.. remove the ‘using’ block around the MemoryStream and change the ‘leaveOpen’ parameter to 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;
}
}
This then comes up with..
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.
I can’t win.. (unless I’m missing something obvious) I’ve tried various things, like putting a try/finally around the block, and Disposing of the MemoryStream in there, but it either says that I’m disposing of it twice, or not at all !!
That is sometimes the problem with running CodeAnalysis, you sometimes you simply cannot win and you have to choose the lesser evil™.
In this situation, I believe the correct implementation is the second example. Why? According to .NET Reflector, the implementation of
GZipStream.Dispose()will dispose of the theMemoryStreamfor you as GZipStream owns the MemoryStream.Relevant parts of
GZipStreamclass below:As you wouldn’t want to disable the rule entirely, you can suppress for this method only using using the
CodeAnalysis.SupressMessageattribute.Note: You will have fill in the full rule name (i.e.
CA2000:?) as I did not know what it was from the error message you posted.HTH,
EDIT:
@CodeInChaos:
Looking deeper at the implementation
DeflateStream.DisposeI believe it still will dispose of the MemoryStream for you regardless of the leaveOpen option as it calls thebase.Dispose().EDIT Ignore the above about
DeflateStream.Dispose. I was looking at the wrong implementation in Reflector. See comments for details.