CA2202, how to solve this case
You should suppress the warnings in this case. Code that deals with disposables should be consistent, and you shouldn't have to care that other classes take ownership of the disposables you created and also call Dispose
on them.
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] Encrypt(string data, byte[] key, byte[] iv) {
using (var memoryStream = new MemoryStream()) {
using (var cryptograph = new DESCryptoServiceProvider())
using (var cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
using (var streamWriter = new StreamWriter(cryptoStream)) {
streamWriter.Write(data);
}
return memoryStream.ToArray();
}
}
UPDATE: In the IDisposable.Dispose documentation you can read this:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times.
It can be argued that this rule exists so that developers can employ the using
statement sanely in a cascade of disposables, like I've shown above (or maybe this is just a nice side-effect). By the same token, then, CA2202 serves no useful purpose, and it should be suppressed project-wise. The real culprit would be a faulty implementation of Dispose
, and CA1065 should take care of that (if it's under your responsibility).
Well, it is accurate, the Dispose() method on these streams will be called more than once. The StreamReader class will take 'ownership' of the cryptoStream so disposing streamWriter will also dispose cryptoStream. Similarly, the CryptoStream class takes over responsibility for the memoryStream.
These are not exactly real bugs, these .NET classes are resilient to multiple Dispose() calls. But if you want to get rid of the warning then you should drop the using statement for these objects. And pain yourself a bit when reasoning what will happen if the code throws an exception. Or shut-up the warning with an attribute. Or just ignore the warning since it is silly.
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.
var memoryStream = new MemoryStream();
using (var cryptograph = new DESCryptoServiceProvider())
using (var writer = new StreamWriter(new CryptoStream(memoryStream, ...)))
{
writer.Write(data);
}
return memoryStream.ToArray();