¿Alguien puede decirme cómo eliminar todas las advertencias CA2202 del siguiente código?
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();
}
}
Advertencia 7 CA2202: Microsoft.Usage: El objeto 'cryptoStream' se puede eliminar más de una vez en el método 'CryptoServices.Encrypt (string, byte [], byte [])'. Para evitar generar una System.ObjectDisposedException, no debe llamar a Dispose más de una vez en un objeto .: Líneas: 34
Advertencia 8 CA2202: Microsoft.Usage: El objeto 'memoryStream' se puede eliminar más de una vez en el método 'CryptoServices.Encrypt (string, byte [], byte [])'. Para evitar generar una System.ObjectDisposedException, no debe llamar a Dispose más de una vez en un objeto .: Líneas: 34, 37
Necesita Visual Studio Code Analysis para ver estas advertencias (estas no son advertencias del compilador de C #).
fuente
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
" - asegúrese de tener unausing System.Diagnostics.CodeAnalysis;
declaración " " en su bloque de usos.Respuestas:
Esto se compila sin previo aviso:
Edite en respuesta a los comentarios: Acabo de verificar nuevamente que este código no genera la advertencia, mientras que el original sí. En el código original,
CryptoStream.Dispose()
yMemoryStream().Dispose(
) en realidad se llaman dos veces (lo que puede ser un problema o no).El código modificado funciona de la siguiente manera: las referencias se establecen en
null
, tan pronto como la responsabilidad de la eliminación se transfiere a otro objeto. Por ejemplo,memoryStream
se establece ennull
después de que la llamada alCryptoStream
constructor se haya realizado correctamente.cryptoStream
se establece ennull
, después de que la llamada alStreamWriter
constructor se haya realizado correctamente. Si no ocurre ninguna excepción,streamWriter
se desecha en elfinally
bloque y, a su vez , se eliminaCryptoStream
yMemoryStream
.fuente
Debe suprimir las advertencias en este caso. El código que se ocupa de los desechables debe ser coherente y no debería tener que preocuparse de que otras clases se apropien de los desechables que haya creado y también los utilicen
Dispose
.ACTUALIZACIÓN: En la documentación de IDisposable.Dispose puede leer esto:
Se puede argumentar que esta regla existe para que los desarrolladores puedan emplear la
using
declaración con cordura en una cascada de desechables, como he mostrado anteriormente (o tal vez esto sea solo un efecto secundario agradable). De la misma manera, CA2202 no tiene ningún propósito útil, y debe suprimirse por proyecto. El verdadero culpable sería una implementación defectuosa deDispose
, y CA1065 debería encargarse de eso (si es bajo su responsabilidad).fuente
Bueno, es preciso, el método Dispose () en estos flujos se llamará más de una vez. La clase StreamReader tomará la 'propiedad' del cryptoStream, por lo que eliminar streamWriter también eliminará cryptoStream. De manera similar, la clase CryptoStream asume la responsabilidad de memoryStream.
Estos no son exactamente errores reales, estas clases .NET son resistentes a múltiples llamadas Dispose (). Pero si desea deshacerse de la advertencia, debe eliminar la instrucción using para estos objetos. Y sufra un poco al razonar qué pasará si el código arroja una excepción. O cierre la advertencia con un atributo. O simplemente ignore la advertencia ya que es una tontería.
fuente
using
declaraciones deberían quedarse. Estas advertencias son realmente tontas.using
declaraciones. Simplemente se siente mal confiar en otro objeto para deshacerse de un objeto que creé. Para este código, está bien, pero hay muchas implementaciones deStream
yTextWriter
por ahí (no solo en el BCL). El código para usarlos todos debe ser coherente.XmlDocument.Save()
método llamaráDispose
al parámetro proporcionado? No lo veo en la documentación deSave(XmlWriter)
(donde estoy experimentando el error FxCop), o en elSave()
método en sí, o en la documentación delXmlDocument
mismo.Cuando se elimina un StreamWriter , automáticamente eliminará el Stream envuelto (aquí: CryptoStream ). CryptoStream también elimina automáticamente el Stream envuelto (aquí: el MemoryStream ).
Entonces, su MemoryStream es eliminado tanto por CryptoStream como por la declaración using . Y su CryptoStream es eliminado por StreamWriter y la declaración de uso externa .
Después de un poco de experimentación, parece imposible deshacerse completamente de las advertencias. Teóricamente, MemoryStream debe eliminarse, pero, en teoría, ya no podría acceder a su método ToArray. Prácticamente, no es necesario eliminar un MemoryStream, por lo que optaría por esta solución y suprimiría la advertencia CA2000.
fuente
Haría esto usando
#pragma warning disable
.Las Pautas de .NET Framework recomiendan implementar IDisposable.Dispose de tal manera que se pueda llamar varias veces. De la descripción de MSDN de IDisposable .
Por lo tanto, la advertencia parece no tener sentido:
Supongo que se podría argumentar que la advertencia puede ser útil si está utilizando un objeto IDisposable mal implementado que no sigue las pautas de implementación estándar. Pero cuando usa clases de .NET Framework como lo está haciendo, diría que es seguro suprimir la advertencia usando un #pragma. Y en mi humilde opinión, esto es preferible a pasar por aros como se sugiere en la documentación de MSDN para esta advertencia .
fuente
#pragma warning disable
solo se puede utilizar para suprimir las advertencias del compilador. Para suprimir una advertencia de Análisis de código, debe utilizar un atributo.Me enfrenté a problemas similares en mi código.
Parece que todo el asunto CA2202 se activa porque
MemoryStream
se puede eliminar si se produce una excepción en el constructor (CA2000).Esto podría resolverse así:
Tenga en cuenta que tenemos que devolver el
memoryStream
interior de la últimausing
declaración (línea 10) porquecryptoStream
se elimina en la línea 11 (porque se usa en lastreamWriter
using
declaración), lo que llevamemoryStream
a obtener también en la línea 11 (porquememoryStream
se usa para crearcryptoStream
).Al menos este código funcionó para mí.
EDITAR:
Por gracioso que parezca, descubrí que si reemplaza el
GetMemoryStream
método con el siguiente código,obtienes el mismo resultado.
fuente
El cryptostream se basa en el memorystream.
Lo que parece estar sucediendo es que cuando se elimina el flujo criptográfico (al final del uso), el flujo de memoria también se elimina, entonces el flujo de memoria se elimina de nuevo.
fuente
Quería resolver esto de la manera correcta, es decir, sin suprimir las advertencias y desechar correctamente todos los objetos desechables.
Saqué 2 de los 3 flujos como campos y los eliminé en el
Dispose()
método de mi clase. Sí, la implementación de laIDisposable
interfaz puede no ser necesariamente lo que está buscando, pero la solución parece bastante limpia en comparación con lasdispose()
llamadas desde todos los lugares aleatorios del código.fuente
Fuera del tema, pero le sugiero que utilice una técnica de formato diferente para agrupar
using
s:También recomiendo usar
var
s aquí para evitar repeticiones de nombres de clases realmente largos.PS Gracias a @ShellShock para señalar que no puedo omitir para los apoyos primero
using
ya que haríamemoryStream
en lareturn
declaración fuera del alcance.fuente
if
s (aunque no recomendaría esta técnica para otra cosa que no seausing
s).return
declaración. Tan verdadero. Edité la respuesta para reflejar esto.using
sin llaves hace que el código sea más frágil (piense en años de diferencias y fusiones). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.html¡Evite todos los usos y utilice Dispose-Calls anidados!
fuente
using
en este caso.Solo quería desenvolver el código para que podamos ver múltiples llamadas a
Dispose
los objetos:Si bien la mayoría de las clases .NET son (con suerte) resistentes al error de múltiples llamadas a
.Dispose
, no todas las clases son tan defensivas contra el mal uso del programador.FX Cop lo sabe y le advierte.
Tiene algunas opciones;
Dispose
una vez a cualquier objeto; no useusing
fuente
Usé este tipo de código que toma bytes [] y devuelve bytes [] sin usar flujos
De esta forma, todo lo que tiene que hacer es la conversión de cadena a byte [] usando codificaciones.
fuente