Can anybody tell me how to remove all CA2202 warnings from the following code?
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();
}
}
Warning 7 CA2202 : Microsoft.Usage : Object 'cryptoStream' can be disposed more than once in method 'CryptoServices.Encrypt(string, byte[], byte[])'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 34
Warning 8 CA2202 : Microsoft.Usage : Object 'memoryStream' can be disposed more than once in method 'CryptoServices.Encrypt(string, byte[], byte[])'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 34, 37
You need Visual Studio Code Analysis to see these warnings (these are not c# compiler warnings).
The cryptostream is based on the memorystream.
What appears to be happening is that when the crypostream is disposed (at end of using) the memorystream is also disposed, then the memorystream is disposed again.
I wanted to solve this the right way - that is without suppressing the warnings and rightly disposing all disposable objects.
I pulled out 2 of the 3 streams as fields and disposed them in the
Dispose()
method of my class. Yes, implementing theIDisposable
interface might not necessarily be what you are looking for but the solution looks pretty clean as compared todispose()
calls from all random places in the code.When a StreamWriter is disposed, it will automatically dispose the wrapped Stream (here: the CryptoStream). CryptoStream also automatically disposes the wrapped Stream (here: the MemoryStream).
So your MemoryStream is disposed both by the CryptoStream and the using statement. And your CryptoStream is disposed by the StreamWriter and the outer using statement.
After some experimentation, it seems to be impossible to get rid of warnings completely. Theorectically, the MemoryStream needs to be disposed, but then you theoretically couldn't access its ToArray method anymore. Practically, a MemoryStream does not need to be disposed, so I'd go with this solution and suppress the CA2000 warning.
Avoid all usings and use nested Dispose-Calls!
This compiles without warning:
Edit in response to the comments: I just verified again that this code does not generate the warning, while the original one does. In the original code,
CryptoStream.Dispose()
andMemoryStream().Dispose(
) are actually called twice (which may or may not be a problem).The modified code works as follows: references are set to
null
, as soon as responsibilty for disposing is transferred to another object. E.g.memoryStream
is set tonull
after the call toCryptoStream
constructor succeeded.cryptoStream
is set tonull
, after the call toStreamWriter
constructor succeeded. If no exception occurs,streamWriter
is disposed in thefinally
block and will in turn disposeCryptoStream
andMemoryStream
.Off-topic but I would suggest you to use a different formatting technique for grouping
using
s:I also advocate using
var
s here to avoid repetitions of really long class names.P.S. Thanks to @ShellShock for pointing out I can't omit braces for first
using
as it would makememoryStream
inreturn
statement out of the scope.