Czy ktoś może mi powiedzieć, jak usunąć wszystkie ostrzeżenia CA2202 z następującego kodu?
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();
}
}
Ostrzeżenie 7 CA2202: Microsoft.Usage: Obiekt „cryptoStream” można usunąć więcej niż raz w metodzie „CryptoServices.Encrypt (string, byte [], byte [])”. Aby uniknąć generowania wyjątku System.ObjectDisposedException, nie należy wywoływać metody Dispose na obiekcie więcej niż jeden raz .: Wiersze: 34
Ostrzeżenie 8 CA2202: Microsoft.Usage: Obiekt „memoryStream” można usunąć więcej niż raz w metodzie „CryptoServices.Encrypt (string, byte [], byte [])”. Aby uniknąć generowania wyjątku System.ObjectDisposedException, nie należy wywoływać metody Dispose na obiekcie więcej niż jeden raz .: Lines: 34, 37
Potrzebujesz analizy kodu programu Visual Studio, aby wyświetlić te ostrzeżenia (nie są to ostrzeżenia kompilatora C #).
źródło
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
” - upewnij się, żeusing System.Diagnostics.CodeAnalysis;
w bloku użycia znajduje się wyrażenie „ ”.Odpowiedzi:
To kompiluje się bez ostrzeżenia:
Edytuj w odpowiedzi na komentarze: Właśnie ponownie zweryfikowałem, że ten kod nie generuje ostrzeżenia, podczas gdy oryginalny. W oryginalnym kodzie
CryptoStream.Dispose()
iMemoryStream().Dispose(
) są w rzeczywistości wywoływane dwukrotnie (co może, ale nie musi, stanowić problem).Zmodyfikowany kod działa w następujący sposób: referencje są ustawiane na
null
, gdy tylko odpowiedzialność za usunięcie zostanie przeniesiona na inny obiekt. EgmemoryStream
jest ustawiony nanull
po pomyślnym wywołaniuCryptoStream
konstruktora.cryptoStream
jest ustawiona nanull
, po pomyślnym wywołaniuStreamWriter
konstruktora. Jeśli nie wystąpi żaden wyjątek,streamWriter
zostanie usunięty wfinally
bloku i z kolei usunieCryptoStream
iMemoryStream
.źródło
W takim przypadku należy wyłączyć ostrzeżenia. Kod, który dotyczy artykułów jednorazowego użytku, powinien być spójny i nie powinieneś martwić się, że inne klasy przejmują własność stworzonych przez Ciebie artykułów jednorazowego użytku, a także
Dispose
je wywołują .AKTUALIZACJA: W dokumentacji IDisposable.Dispose można przeczytać to:
Można argumentować, że ta reguła istnieje, aby programiści mogli
using
rozsądnie zastosować instrukcję w kaskadzie urządzeń jednorazowego użytku, jak pokazałem powyżej (a może jest to po prostu fajny efekt uboczny). Z tego samego powodu CA2202 nie służy żadnemu pożytecznemu celowi i powinno być stłumione z punktu widzenia projektu. Prawdziwym winowajcą byłaby wadliwa implementacjaDispose
, a CA1065 powinien się tym zająć (jeśli za to odpowiadasz).źródło
Cóż, to prawda, metoda Dispose () na tych strumieniach będzie wywoływana więcej niż raz. Klasa StreamReader przejmie „własność” cryptoStream, więc usunięcie streamWriter spowoduje również usunięcie cryptoStream. Podobnie klasa CryptoStream przejmuje odpowiedzialność za memoryStream.
Nie są to do końca prawdziwe błędy, te klasy .NET są odporne na wiele wywołań metody Dispose (). Ale jeśli chcesz pozbyć się ostrzeżenia, powinieneś porzucić instrukcję using dla tych obiektów. I zrób sobie trochę bólu, myśląc, co się stanie, jeśli kod wyrzuci wyjątek. Lub zamknij ostrzeżenie za pomocą atrybutu. Lub po prostu zignoruj ostrzeżenie, ponieważ jest głupie.
źródło
using
oświadczenia powinny pozostać. Te ostrzeżenia są naprawdę głupie.using
oświadczeń. Po prostu czuję się źle, polegając na innym obiekcie, aby pozbyć się obiektu, który stworzyłem. W przypadku tego kodu jest to w porządku, ale istnieje wiele implementacjiStream
iTextWriter
tam (nie tylko w BCL). Kod użycia ich wszystkich powinien być spójny.XmlDocument.Save()
metoda będzie wywoływać podanyDispose
parametr? Nie widzę tego w dokumentacjiSave(XmlWriter)
(gdzie doświadczam błędu FxCop), wSave()
samej metodzie ani w samej dokumentacjiXmlDocument
.Kiedy StreamWriter zostanie usunięty, automatycznie usunie opakowany Stream (tutaj: CryptoStream ). CryptoStream również automatycznie usuwa opakowany strumień (tutaj: MemoryStream ).
Więc twój MemoryStream jest usuwany zarówno przez CryptoStream, jak i instrukcję using . Twój CryptoStream jest usuwany przez StreamWriter i zewnętrzną instrukcję using .
Po pewnych eksperymentach wydaje się, że całkowite pozbycie się ostrzeżeń wydaje się niemożliwe. Teoretycznie MemoryStream musi zostać usunięty, ale teoretycznie nie można już uzyskać dostępu do jego metody ToArray. Praktycznie MemoryStream nie trzeba pozbywać się, więc wybrałbym to rozwiązanie i pominął ostrzeżenie CA2000.
źródło
Zrobiłbym to za pomocą
#pragma warning disable
.Wytyczne .NET Framework zalecają zaimplementowanie IDisposable.Dispose w taki sposób, aby można było go wielokrotnie wywoływać. Z opisu IDisposable.Dispose w witrynie MSDN :
Dlatego ostrzeżenie wydaje się prawie bez znaczenia:
Myślę, że można by argumentować, że ostrzeżenie może być pomocne, jeśli używasz źle zaimplementowanego obiektu IDisposable, który nie jest zgodny ze standardowymi wytycznymi dotyczącymi implementacji. Ale kiedy używasz klas z .NET Framework, tak jak robisz, powiedziałbym, że bezpiecznie jest zignorować ostrzeżenie za pomocą #pragma. I IMHO jest to lepsze od przechodzenia przez obręcze, jak sugeruje dokumentacja MSDN dla tego ostrzeżenia .
źródło
#pragma warning disable
może służyć tylko do pomijania ostrzeżeń kompilatora. Aby pominąć ostrzeżenie analizy kodu, musisz użyć atrybutu.Miałem podobne problemy w moim kodzie.
Wygląda na to, że wyzwalany jest cały CA2202, ponieważ
MemoryStream
można go usunąć, jeśli wystąpi wyjątek w konstruktorze (CA2000).Można to rozwiązać w następujący sposób:
Zauważ, że musimy zwrócić
memoryStream
wnętrze ostatniejusing
instrukcji (linia 10), ponieważcryptoStream
zostaje usunięta w linii 11 (ponieważ jest używana wstreamWriter
using
instrukcji), co prowadzimemoryStream
domemoryStream
usunięcia również w linii 11 (ponieważ jest używana do tworzeniacryptoStream
).Przynajmniej ten kod działał dla mnie.
EDYTOWAĆ:
Choć może to zabrzmieć zabawnie, odkryłem, że jeśli zastąpisz
GetMemoryStream
metodę następującym kodem,uzyskasz ten sam wynik.
źródło
Cryptostream jest oparty na memorystream.
Wydaje się, że dzieje się tak, że kiedy strumień kryptograficzny jest usuwany (pod koniec używania), strumień pamięci jest również usuwany, a następnie strumień pamięci jest usuwany ponownie.
źródło
Chciałem rozwiązać ten problem we właściwy sposób - to znaczy bez tłumienia ostrzeżeń i właściwego usuwania wszystkich przedmiotów jednorazowego użytku.
Wyciągnąłem 2 z 3 strumieni jako pola i umieściłem je w
Dispose()
metodzie mojej klasy. Tak, implementacjaIDisposable
interfejsu może niekoniecznie być tym, czego szukasz, ale rozwiązanie wygląda całkiem czysto w porównaniu dodispose()
wywołań ze wszystkich losowych miejsc w kodzie.źródło
Nie na temat, ale sugerowałbym użycie innej techniki formatowania do grupowania
using
s:Zalecam również użycie
var
tutaj s, aby uniknąć powtórzeń naprawdę długich nazw klas.PS Dziękuję @ShellShock za wskazanie, że nie mogę pominąć nawiasów klamrowych na początku,
using
ponieważ spowodowałoby tomemoryStream
wreturn
instrukcji poza zakresem.źródło
if
s (chociaż nie radziłbym tej techniki dla niczego innego niżusing
s).return
oświadczenie. Tak prawdziwe. Zredagowałem odpowiedź, aby to odzwierciedlić.using
nawiasów klamrowych sprawia, że kod jest bardziej kruchy (pomyśl o latach różnic i połączeń). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.htmlUnikaj wszelkich zastosowań i używaj zagnieżdżonych wywołań Dispose!
źródło
using
w takim przypadku należy unikać .Chciałem tylko rozpakować kod, abyśmy mogli zobaczyć wiele wywołań
Dispose
obiektów:Chociaż większość klas .NET jest (miejmy nadzieję) odporna na błąd wielokrotnych wywołań
.Dispose
, nie wszystkie klasy są tak samo odporne na nadużycia programisty.FX Cop wie o tym i ostrzega.
Masz kilka możliwości;
Dispose
raz na dowolny obiekt; nie używajusing
źródło
Użyłem tego rodzaju kodu, który pobiera bajt [] i zwraca bajt [] bez użycia strumieni
W ten sposób wszystko, co musisz zrobić, to przekonwertować ciąg znaków na bajt [] za pomocą kodowania.
źródło