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).
I was faced with similar issues in my code.
Looks like the whole CA2202 thing is triggered because
MemoryStream
can be disposed if exception occurs in constructor (CA2000).This could be resolved like this:
Notice that we have to return the
memoryStream
inside the lastusing
statement (line 10) becausecryptoStream
gets disposed at line 11 (because it's used instreamWriter
using
statement), which leadsmemoryStream
to get also disposed at line 11 (becausememoryStream
is used to create thecryptoStream
).At least this code worked for me.
EDIT:
Funny as it may sound, I discovered that if you replace the
GetMemoryStream
method with the following code,you get the same result.
I just wanted to unwrap the code so we can see multiple calls to
Dispose
on the objects:While most .NET class are (hopefully) resilient against the mistake of multiple calls to
.Dispose
, not all classes are as defensive against programmer misuse.FX Cop knows this, and warns you.
You have a few choices;
Dispose
once on any object; don't useusing
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.
I would do this using
#pragma warning disable
.The .NET Framework Guidelines recommend to implement IDisposable.Dispose in such a way that it can be called multiple times. From the MSDN description of IDisposable.Dispose:
Therefore the warning seems to be almost meaningless:
I guess it could be argued that the warning may be helpful if you're using a badly-implemented IDisposable object that does not follow the standard implementation guidelines. But when using classes from the .NET Framework like you are doing, I'd say it's safe to suppress the warning using a #pragma. And IMHO this is preferable to going through hoops as suggested in the MSDN documentation for this warning.
I used this kind of code that takes byte[] and return byte[] without using streams
This way all you have to do is conversion from string to byte[] using encodings.
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.UPDATE: In the IDisposable.Dispose documentation you can read this:
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 ofDispose
, and CA1065 should take care of that (if it's under your responsibility).