Come determinare HResult per System.IO.IOException?

La proprietà System.Exception.HResult è protetta. Come posso sbirciare all’interno di un’eccezione e ottenere l’HResult senza ricorrere a riflessioni o altri brutti hack?


Ecco la situazione:
Voglio scrivere uno strumento di backup, che apre e legge i file su un sistema. Apro il file con FileAccess.Read e FileShare.ReadWrite, secondo questa guida , perché non mi interessa se il file è aperto per la scrittura al momento in cui l’ho letto.

In alcuni casi, quando un file che sto leggendo è aperto da un’altra app, il metodo System.IO.FileStream.Read () genera un System.IO.IOException, “Il processo non può accedere al file perché un altro processo ha bloccato una porzione di il file”. Questo è l’ errore 33 o penso HResult 0x80070021. [ EDIT : credo che questo possa essere restituito quando un altro processo chiama LockFileEx per bloccare un intervallo di byte all’interno di un file.]

Mi piacerebbe mettere in pausa e riprovare quando ricevo questo errore. Penso che questa sia l’azione appropriata da portare qui. Se il processo di blocco rilascia rapidamente il blocco dell’intervallo di byte, posso continuare a leggere il file.

Come posso distinguere una IOException per questo motivo, da altri? Posso pensare a questi modi:

    • riflessione privata – non voglio farlo. La perfezione puzzerà.
    • chiama Exception.ToString () e analizza la stringa. Sembra hacky. Non funzionerà nelle versioni i18n.

    Non mi piacciono queste opzioni. Non c’è un modo migliore, più pulito?


    Ho appena cercato e trovato System.Runtime.InteropServices.Marshal.GetHRForException . Ciò restituirà un uint come 0x80070021?

    Per. Net Framework 4.5 e versioni successive, è ansible utilizzare la proprietà Exception.HResult :

     int hr = ex.HResult; 

    Per le versioni precedenti, è ansible utilizzare Marshal.GetHRForException per recuperare HResult, ma questo ha effetti collaterali significativi e non è raccomandato :

     int hr = Marshal.GetHRForException(ex); 

    Per quello che vale, System.Exception.HResult non è più protetto in .NET 4.5 – solo il setter è protetto. Ciò non aiuta con il codice che potrebbe essere compilato con più di una versione del framework.

    Puoi anche utilizzare l’interfaccia ISerializable :

     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"); } } 

    In questo caso la proprietà di CanRead aiuto?
    es. chiama CanRead , se restituisce true, chiama Read()

    Hai profilato uno di questi casi? Immagino che il metodo di riflessione non sia poi così lento, soprattutto rispetto a tutti gli altri lavori che la tua app farà e alla frequenza con cui è probabile che si verifichi questa eccezione.

    Se risulta essere un collo di bottiglia, puoi cercare nella cache alcune operazioni di riflessione o generare IL dinamico per recuperare la proprietà.