Alguém pode me dizer como remover todos os avisos CA2202 do código a seguir?
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();
}
}
Aviso 7 CA2202: Microsoft.Usage: O objeto 'cryptoStream' pode ser descartado mais de uma vez no método 'CryptoServices.Encrypt (string, byte [], byte [])'. Para evitar a geração de uma System.ObjectDisposedException, você não deve chamar Dispose mais de uma vez em um objeto .: Lines: 34
Aviso 8 CA2202: Microsoft.Usage: O objeto 'memoryStream' pode ser descartado mais de uma vez no método 'CryptoServices.Encrypt (string, byte [], byte [])'. Para evitar a geração de System.ObjectDisposedException, você não deve chamar Dispose mais de uma vez em um objeto .: Linhas: 34, 37
Você precisa do Visual Studio Code Analysis para ver esses avisos (não são avisos do compilador c #).
fonte
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
" - certifique-se de ter umausing System.Diagnostics.CodeAnalysis;
declaração " " em seu bloco de uso.Respostas:
Compila sem aviso:
Editar em resposta aos comentários: Acabei de verificar novamente que este código não gera o aviso, enquanto o original sim. No código original,
CryptoStream.Dispose()
eMemoryStream().Dispose(
) são chamados duas vezes (o que pode ou não ser um problema).O código modificado funciona da seguinte maneira: as referências são definidas
null
como, assim que a responsabilidade pelo descarte é transferida para outro objeto. Por exemplo,memoryStream
é definido comonull
após a chamada aoCryptoStream
construtor ser bem-sucedida.cryptoStream
está configurado paranull
, após a chamada aoStreamWriter
construtor ser bem-sucedida. Se nenhuma exceção ocorrer,streamWriter
é descartado nofinally
bloco e, por sua vez, descartaráCryptoStream
eMemoryStream
.fonte
Você deve suprimir os avisos neste caso. O código que lida com descartáveis deve ser consistente, e você não deve se preocupar se outras classes se apropriam dos descartáveis que você criou e também recorrem
Dispose
a eles.ATUALIZAÇÃO: Na documentação IDisposable.Dispose você pode ler isto:
Pode-se argumentar que essa regra existe para que os desenvolvedores possam empregar a
using
instrução de maneira saudável em uma cascata de descartáveis, como mostrei acima (ou talvez este seja apenas um bom efeito colateral). Da mesma forma, então, CA2202 não tem nenhum propósito útil e deve ser suprimido em termos de projeto. O verdadeiro culpado seria uma implementação incorreta doDispose
, e o CA1065 deve cuidar disso (se estiver sob sua responsabilidade).fonte
Bem, é preciso, o método Dispose () nesses fluxos será chamado mais de uma vez. A classe StreamReader terá 'propriedade' de cryptoStream, portanto, descartar streamWriter também descartará cryptoStream. Da mesma forma, a classe CryptoStream assume a responsabilidade pelo memoryStream.
Esses bugs não são exatamente reais, essas classes .NET são resilientes a várias chamadas Dispose (). Mas se você quiser se livrar do aviso, você deve descartar a instrução using para esses objetos. E se preocupe um pouco ao raciocinar o que acontecerá se o código lançar uma exceção. Ou feche o aviso com um atributo. Ou simplesmente ignore o aviso, pois é bobo.
fonte
using
afirmações deveriam ficar. Esses avisos são realmente bobos.using
declarações. Parece errado confiar em outro objeto para descartar um objeto que eu criei. Para este código, está tudo bem, mas existem muitas implementações deStream
eTextWriter
por aí (não apenas no BCL). O código para usar todos eles deve ser consistente.XmlDocument.Save()
método irá chamarDispose
o parâmetro fornecido? Eu não vejo isso na documentação doSave(XmlWriter)
(onde estou enfrentando o bug FxCop), ou noSave()
próprio método, ou na documentação deleXmlDocument
mesmo.Quando um StreamWriter é descartado, ele automaticamente descarta o Stream encapsulado (aqui: o CryptoStream ). CryptoStream também descarta automaticamente o Stream empacotado (aqui: o MemoryStream ).
Portanto, seu MemoryStream é descartado tanto pelo CryptoStream quanto pela instrução using . E seu CryptoStream é descartado pelo StreamWriter e pela instrução externa using .
Depois de alguma experimentação, parece ser impossível se livrar completamente dos avisos. Teoricamente, o MemoryStream precisa ser descartado, mas teoricamente você não pode mais acessar seu método ToArray. Praticamente, um MemoryStream não precisa ser descartado, então eu escolheria esta solução e suprimiria o aviso CA2000.
fonte
Eu faria isso usando
#pragma warning disable
.As diretrizes do .NET Framework recomendam implementar IDisposable.Dispose de forma que possa ser chamado várias vezes. Da descrição do MSDN de IDisposable.Dispose :
Portanto, o aviso parece quase sem sentido:
Acho que pode-se argumentar que o aviso pode ser útil se você estiver usando um objeto IDisposable mal implementado que não segue as diretrizes de implementação padrão. Mas ao usar classes do .NET Framework como você está fazendo, eu diria que é seguro suprimir o aviso usando um #pragma. E, IMHO, isso é preferível a passar por obstáculos, conforme sugerido na documentação do MSDN para este aviso .
fonte
#pragma warning disable
só pode ser usado para suprimir avisos do compilador. Para suprimir um aviso de análise de código, você precisa usar um atributo.Eu me deparei com problemas semelhantes em meu código.
Parece que todo o CA2202 é acionado porque
MemoryStream
pode ser descartado se ocorrer uma exceção no construtor (CA2000).Isso poderia ser resolvido assim:
Observe que temos que retornar o
memoryStream
interior da últimausing
instrução (linha 10) porquecryptoStream
é descartado na linha 11 (porque é usado nastreamWriter
using
instrução), o que levamemoryStream
a também ser descartado na linha 11 (porquememoryStream
é usado para criar ocryptoStream
).Pelo menos esse código funcionou para mim.
EDITAR:
Por mais engraçado que pareça, descobri que se você substituir o
GetMemoryStream
método pelo código a seguir,você obtém o mesmo resultado.
fonte
O cryptostream é baseado no fluxo de memória.
O que parece estar acontecendo é que quando o crypostream é descartado (no final do uso), o fluxo de memória também é descartado, então o fluxo de memória é descartado novamente.
fonte
Eu queria resolver isso da maneira certa - ou seja, sem suprimir os avisos e descartar corretamente todos os objetos descartáveis.
Retirei 2 dos 3 streams como campos e os dispensei no
Dispose()
método da minha classe. Sim, implementar aIDisposable
interface pode não ser necessariamente o que você está procurando, mas a solução parece bem limpa em comparação com asdispose()
chamadas de todos os lugares aleatórios no código.fonte
Fora do tópico, mas eu sugiro que você use uma técnica de formatação diferente para agrupar
using
s:Também defendo o uso de
var
s aqui para evitar repetições de nomes de classe muito longos.PS: Obrigado a @ShellShock por apontar que não posso omitir os colchetes primeiro,
using
pois isso fariamemoryStream
em umareturn
declaração fora do escopo.fonte
if
s (embora eu não recomende essa técnica para outra coisa senãousing
s).return
declaração. Tão verdade. Eu editei a resposta para refletir isso.using
sem chaves torna o código mais frágil (pense em anos de diferenças e mesclagens). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.htmlEvite todos os usos e use Dispose-Calls aninhadas!
fonte
using
neste caso.Eu só queria desembrulhar o código para que possamos ver várias chamadas para
Dispose
nos objetos:Embora a maioria das classes .NET sejam (esperançosamente) resilientes contra o erro de várias chamadas para
.Dispose
, nem todas as classes são tão defensivas contra o uso indevido do programador.FX Cop sabe disso e avisa você.
Você tem poucas escolhas;
Dispose
uma vez em qualquer objeto; não useusing
fonte
Eu usei esse tipo de código que pega byte [] e retorna byte [] sem usar streams
Desta forma, tudo o que você precisa fazer é converter de string em byte [] usando codificações.
fonte