Kann mir jemand sagen, wie ich alle CA2202-Warnungen aus dem folgenden Code entfernen kann?
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();
}
}
Warnung 7 CA2202: Microsoft.Usage: Das Objekt 'cryptoStream' kann in der Methode 'CryptoServices.Encrypt (Zeichenfolge, Byte [], Byte [])' mehrmals entsorgt werden. Um zu vermeiden, dass eine System.ObjectDisposedException generiert wird, sollten Sie Dispose nicht mehr als einmal für ein Objekt aufrufen: Zeilen: 34
Warnung 8 CA2202: Microsoft.Usage: Das Objekt 'memoryStream' kann in der Methode 'CryptoServices.Encrypt (Zeichenfolge, Byte [], Byte [])' mehrmals entsorgt werden. Um zu vermeiden, dass eine System.ObjectDisposedException generiert wird, sollten Sie Dispose nicht mehr als einmal für ein Objekt aufrufen: Zeilen: 34, 37
Sie benötigen Visual Studio Code Analysis, um diese Warnungen anzuzeigen (dies sind keine C # -Compiler-Warnungen).
quelle
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
" -using System.Diagnostics.CodeAnalysis;
Stellen Sie sicher, dass Ihr Verwendungsblock eine " " -Anweisung enthält.Antworten:
Dies wird ohne Vorwarnung kompiliert:
Bearbeiten als Antwort auf die Kommentare: Ich habe gerade erneut überprüft, dass dieser Code die Warnung nicht generiert, während der ursprüngliche Code dies tut. Im Originalcode werden
CryptoStream.Dispose()
undMemoryStream().Dispose(
) tatsächlich zweimal aufgerufen (was ein Problem sein kann oder nicht).Der geänderte Code funktioniert wie folgt: Verweise werden auf gesetzt
null
, sobald die Verantwortung für die Entsorgung auf ein anderes Objekt übertragen wird. WirdmemoryStream
beispielsweise auf gesetzt,null
nachdem der Aufruf desCryptoStream
Konstruktors erfolgreich war.cryptoStream
wird auf gesetztnull
, nachdem der Aufruf desStreamWriter
Konstruktors erfolgreich war. Wenn keine Ausnahme auftritt,streamWriter
wird imfinally
Block entsorgt und wird wiederumCryptoStream
und entsorgenMemoryStream
.quelle
Sie sollten in diesem Fall die Warnungen unterdrücken. Code, der sich mit Einwegartikeln befasst, sollte konsistent sein, und Sie sollten sich nicht darum kümmern müssen, dass andere Klassen das Eigentum an den von Ihnen erstellten Einwegartikeln übernehmen und diese auch aufrufen
Dispose
.UPDATE: In der IDisposable.Dispose- Dokumentation können Sie Folgendes lesen:
Es kann argumentiert werden, dass diese Regel existiert, damit Entwickler die
using
Aussage vernünftig in einer Kaskade von Einwegartikeln verwenden können, wie ich oben gezeigt habe (oder vielleicht ist dies nur ein netter Nebeneffekt). Aus dem gleichen Grund erfüllt CA2202 keinen nützlichen Zweck und sollte projektbezogen unterdrückt werden. Der eigentliche Schuldige wäre eine fehlerhafte Implementierung vonDispose
, und CA1065 sollte sich darum kümmern (wenn es in Ihrer Verantwortung liegt).quelle
Nun, es ist richtig, die Dispose () -Methode für diese Streams wird mehrmals aufgerufen. Die StreamReader-Klasse übernimmt den Besitz des cryptoStream, sodass durch das Entsorgen von streamWriter auch cryptoStream entsorgt wird. Ebenso übernimmt die CryptoStream-Klasse die Verantwortung für den memoryStream.
Dies sind keine echten Fehler. Diese .NET-Klassen sind gegenüber mehreren Dispose () -Aufrufen stabil. Wenn Sie die Warnung jedoch entfernen möchten, sollten Sie die using-Anweisung für diese Objekte löschen. Und schmerzen Sie sich ein wenig, wenn Sie überlegen, was passieren wird, wenn der Code eine Ausnahme auslöst. Oder schließen Sie die Warnung mit einem Attribut. Oder ignorieren Sie einfach die Warnung, da sie albern ist.
quelle
using
Aussagen bleiben sollten. Diese Warnungen sind wirklich dumm.using
Aussagen trotzdem nicht fallen lassen . Es fühlt sich einfach falsch an, sich auf ein anderes Objekt zu verlassen, um ein von mir erstelltes Objekt zu entsorgen. Für diesen Code ist es in Ordnung, aber es gibt viele Implementierungen vonStream
undTextWriter
da draußen (nicht nur auf der BCL). Der Code, um sie alle zu verwenden, sollte konsistent sein.XmlDocument.Save()
MethodeDispose
den angegebenen Parameter aufruft ? Ich sehe es nicht in der Dokumentation vonSave(XmlWriter)
(wo ich den FxCop-Fehler habe), in derSave()
Methode selbst oder in der Dokumentation vonXmlDocument
sich.Wenn ein StreamWriter entsorgt wird, wird der umschlossene Stream automatisch entsorgt (hier: der CryptoStream ). CryptoStream entsorgt auch automatisch den umschlossenen Stream (hier: den MemoryStream ).
Ihr MemoryStream wird also sowohl vom CryptoStream als auch von der using- Anweisung entsorgt . Und Ihr CryptoStream wird vom StreamWriter und der äußeren using- Anweisung entsorgt .
Nach einigen Experimenten scheint es unmöglich zu sein, Warnungen vollständig zu beseitigen. Theoretisch muss der MemoryStream entsorgt werden, aber theoretisch konnte man nicht mehr auf seine ToArray-Methode zugreifen. Praktisch muss ein MemoryStream nicht entsorgt werden, daher würde ich mich für diese Lösung entscheiden und die CA2000-Warnung unterdrücken.
quelle
Ich würde das mit machen
#pragma warning disable
.In den .NET Framework-Richtlinien wird empfohlen, IDisposable.Dispose so zu implementieren, dass es mehrmals aufgerufen werden kann. Aus der MSDN-Beschreibung von IDisposable.Dispose :
Daher scheint die Warnung fast bedeutungslos zu sein:
Ich denke, es könnte argumentiert werden, dass die Warnung hilfreich sein kann, wenn Sie ein schlecht implementiertes IDisposable-Objekt verwenden, das nicht den Standard-Implementierungsrichtlinien entspricht. Wenn Sie jedoch Klassen aus .NET Framework verwenden, wie Sie es tun, ist es sicher, die Warnung mit einem #pragma zu unterdrücken. Und meiner Meinung nach ist dies dem Durchlaufen von Rahmen vorzuziehen, wie in der MSDN-Dokumentation für diese Warnung vorgeschlagen .
quelle
#pragma warning disable
kann nur zum Unterdrücken von Compiler-Warnungen verwendet werden. Um eine Code-Analyse-Warnung zu unterdrücken, müssen Sie ein Attribut verwenden.Ich hatte ähnliche Probleme in meinem Code.
Es sieht so aus, als ob das gesamte CA2202-Ding ausgelöst wird, da
MemoryStream
es entsorgt werden kann, wenn im Konstruktor (CA2000) eine Ausnahme auftritt.Dies könnte folgendermaßen gelöst werden:
Beachten Sie, dass wir das
memoryStream
Innere der letztenusing
Anweisung (Zeile 10) zurückgebencryptoStream
müssen, da es in Zeile 11 entsorgt wird (weil es in derstreamWriter
using
Anweisung verwendet wird), was dazu führtmemoryStream
, dass es auch in Zeile 11 entsorgt wird (weilmemoryStream
es zum Erstellen der verwendet wirdcryptoStream
).Zumindest hat dieser Code bei mir funktioniert.
BEARBEITEN:
So komisch es auch klingen mag, ich habe festgestellt, dass, wenn Sie die
GetMemoryStream
Methode durch den folgenden Code ersetzen ,Sie erhalten das gleiche Ergebnis.
quelle
Der Kryptostream basiert auf dem Memorystream.
Was zu passieren scheint, ist, dass, wenn der Kryostream (am Ende der Verwendung) auch der Memorystream entsorgt wird, der Memorystream erneut entsorgt wird.
quelle
Ich wollte das richtig lösen - das heißt, ohne die Warnungen zu unterdrücken und alle Einweggegenstände richtig zu entsorgen.
Ich habe 2 der 3 Streams als Felder herausgezogen und sie in der
Dispose()
Methode meiner Klasse angeordnet. Ja, die Implementierung derIDisposable
Schnittstelle ist möglicherweise nicht unbedingt das, wonach Sie suchen, aber die Lösung sieht im Vergleich zudispose()
Aufrufen von allen zufälligen Stellen im Code ziemlich sauber aus.quelle
Off-Topic, aber ich würde Ihnen empfehlen, eine andere Formatierungstechnik für die Gruppierung von
using
s zu verwenden:Ich empfehle auch,
var
hier s zu verwenden, um Wiederholungen von wirklich langen Klassennamen zu vermeiden.PS Dank @ShellShock für den Hinweis auf Ich kann nicht auslassen Klammern für die ersten ,
using
da es machen würde ,memoryStream
inreturn
Anweisung aus dem Rahmen.quelle
if
s tun können (obwohl ich diese Technik für nichts anderes alsusing
s empfehlen würde ).return
Aussage gemeint haben . So wahr. Ich habe die Antwort bearbeitet, um dies widerzuspiegeln.using
ohne Klammern den Code zerbrechlicher macht (denken Sie an jahrelange Unterschiede und Zusammenführungen). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.htmlVermeiden Sie alle Verwendungen und verwenden Sie verschachtelte Entsorgungsaufrufe!
quelle
using
dies in diesem Fall vermeiden sollten .Ich wollte nur den Code auspacken, damit wir mehrere Aufrufe für
Dispose
die Objekte sehen können:Während die meisten .NET-Klassen (hoffentlich) widerstandsfähig gegen den Fehler mehrerer Aufrufe sind,
.Dispose
sind nicht alle Klassen so defensiv gegen den Missbrauch durch Programmierer.FX Cop weiß das und warnt Sie.
Sie haben einige Möglichkeiten;
Dispose
ein Objekt nur einmal auf. nicht benutzenusing
quelle
Ich habe diese Art von Code verwendet, der Byte [] nimmt und Byte [] zurückgibt, ohne Streams zu verwenden
Auf diese Weise müssen Sie lediglich mithilfe von Codierungen von Zeichenfolge zu Byte [] konvertieren.
quelle