2009-06-13 6 views
33

Die Eigenschaft System.Exception.HResult ist geschützt. Wie kann ich in eine Ausnahme hineinschauen und das HResult erhalten, ohne auf Reflektion oder andere hässliche Hacks zurückgreifen zu müssen?Wie ermittle ich das HResult für eine System.IO.IOException?


Hier ist die Situation:
ich ein Backup-Tool zu schreiben, das sich öffnet und liest Dateien auf einem System. Ich öffne die Datei mit FileAccess.Read und FileShare.ReadWrite, nach this guidance, weil es mir egal ist, wenn die Datei zum Zeitpunkt des Lesens zum Schreiben geöffnet ist.

In einigen Fällen löst die Methode System.IO.FileStream.Read(), wenn eine von mir gelesene Datei von einer anderen Anwendung geöffnet wird, eine System.IO.IOException aus: "Der Prozess kann nicht auf die Datei zugreifen, weil ein anderer Prozess vorhanden ist einen Teil der Datei gesperrt ". Das ist error 33 oder ich denke HResult 0x80070021. [EDIT. Ich glaube, das zurückgeführt werden kann, wenn ein anderer Prozess LockFileEx Anrufe innerhalb einer Datei ein Byte-Bereich sperren]

Ich möchte anhalten und wiederholen, wenn ich diesen Fehler. Ich denke, dies ist die geeignete Maßnahme, die hier zu treffen ist. Wenn der Sperrvorgang die Bytebereichssperre schnell freigibt, kann ich mit dem Lesen der Datei fortfahren.

Wie kann ich eine IOException aus diesem Grund von anderen unterscheiden? Ich kann an diese Möglichkeiten denken:

  • private Reflexion - will das nicht tun. Perf wird stinken.
  • Aufruf Exception.ToString() und analysieren Sie die Zeichenfolge. Fühlt sich hacky an. Funktioniert nicht in i18n-Versionen.

Ich mag diese Optionen nicht. Gibt es keinen besseren, saubereren Weg?


Ich habe gerade gesucht und System.Runtime.InteropServices.Marshal.GetHRForException gefunden. Wird das eine URL wie 0x80070021 zurückgeben?

+3

> Private Reflexion - tun Sie das nicht tun wollen. Perf wird stinken. - Exception perf stinkt sowieso, also würde ich mir über den Perfaspekt keine Sorgen machen. Reflection erfordert jedoch FullTrust, ist hässlich und nicht unterstützt und anfällig für Bruch - weshalb sollten Sie es nicht tun. –

Antwort

54

Für .Net Framework 4.5 und höher, können Sie die Exception.HResult Eigenschaft:

int hr = ex.HResult; 

Für ältere Versionen Sie Marshal.GetHRForException verwenden können die HResult zurück zu bekommen, aber das has significant side-effects and is not recommended:

int hr = Marshal.GetHRForException(ex); 
+0

Vielen Dank! Dies erleichtert die Entwicklung im Falle einer C#/COM-Interoperabilität. – rds

+2

+1 Eww, erfordert volles Vertrauen ... Aber es ist trotzdem eine Lösung. – reSPAWNed

+3

Vorsicht vor Nebenwirkungen: "Beachten Sie, dass die Methode ** GetHRForException ** die ** IErrorInfo ** des aktuellen Threads festlegt. Dies kann zu unerwarteten Ergebnissen für Methoden wie die ** ThrowExceptionForHR ** -Methoden führen, die standardmäßig verwendet werden die ** IErrorInfo ** des aktuellen Threads, wenn es gesetzt ist. " – HugoRune

0

Funktioniert CanRead Eigenschaft in diesem Fall?
heißt CanRead nennen, wenn das wahr zurückgibt, rufen Read()

+0

Nein, CanRead ist wahr. Ich glaube, 80070021 ist ein vorübergehender Fehler. Wenn ich das Dokument richtig lese, ist es die empfohlene Vorgehensweise, "eine Weile zu warten und es erneut zu versuchen". – Cheeso

+0

Ist es möglich, dass Sie die Datei zum Lesen geöffnet haben und jemand anders sie geöffnet hat (mit FileShare.Read), der 1. Anrufer kann es nicht mehr lesen? Meinst du das mit Vergänglichkeit? – shahkalpesh

+0

Nein, was ich meine ist, ein anderer Prozess hat FileLock oder FileLockEx (http://msdn.microsoft.com/en-us/library/aa365203.aspx) für die Datei aufgerufen, um einen Bereich innerhalb der Datei zu sperren. Dies wird manchmal als Bytebereichssperre bezeichnet. Irgendwann wird der Sperrvorgang die Bereichssperre freigeben. Das meine ich mit "Transient". – Cheeso

0

Haben Sie eine dieser beiden Fällen profiliert? Ich könnte mir vorstellen, dass die Reflektionsmethode nicht so langsam ist, besonders im Vergleich zu all den anderen Arbeiten, die Ihre App durchführen wird und wie oft diese Ausnahme wahrscheinlich auftritt.

Wenn sich herausstellt, dass es sich um einen Engpass handelt, können Sie einige der Reflexionsoperationen zwischenspeichern oder dynamische IL generieren, um die Eigenschaft abzurufen.

11

Für was es wert ist, System.Exception.HResult ist in .NET 4.5 nicht mehr geschützt - nur der Setter ist geschützt. Das hilft nicht bei Code, der mit mehr als einer Version des Frameworks kompiliert werden kann.

3

Sie können auch die ISerializable Schnittstelle verwenden:

static class IOExceptionExtensions 
{ 
    public static int GetHResult(this IOException ex) 
    { 
     var info = new SerializationInfo(typeof (IOException), new FormatterConverter()); 
     ex.GetObjectData(info, new StreamingContext()); 
     return info.GetInt32("HResult"); 
    } 
} 
Verwandte Themen