2009-06-13 4 views
33

La propriété System.Exception.HResult est protégée. Comment puis-je jeter un coup d'œil à l'intérieur d'une exception et obtenir le résultat sans avoir recours à la réflexion ou à d'autres hacks?Comment puis-je déterminer le paramètre HResult pour une exception System.IO.IO?


est ici la situation:
Je veux écrire un outil de sauvegarde, qui ouvre et lit les fichiers sur un système. J'ouvre le fichier avec FileAccess.Read et FileShare.ReadWrite, selon this guidance, parce que je m'en fous si le fichier est ouvert pour l'écriture au moment où je l'ai lu. Dans certains cas, lorsqu'un fichier que je suis en train de lire est ouvert par une autre application, la méthode System.IO.FileStream.Read() lève une exception System.IO.IOException, "Le processus ne peut pas accéder au fichier car un autre processus a verrouillé une partie du fichier ". C'est error 33, ou je pense que HResult 0x80070021. [EDIT . Je crois que cela peut être retourné lorsqu'un autre processus appelle LockFileEx pour verrouiller une plage d'octets dans un fichier]

Je voudrais faire une pause et une nouvelle tentative quand je reçois cette erreur. Je pense que c'est l'action appropriée à prendre ici. Si le processus de verrouillage libère rapidement le verrou d'octet, alors je peux continuer à lire le fichier. Comment puis-je distinguer une exception IOException pour cette raison, des autres? Je peux penser à ces manières:

  • réflexion privée - ne veux pas faire cela. Perf va puer.
  • appelez Exception.ToString() et analysez la chaîne. Se sent hacky. Ne fonctionnera pas dans les versions i18n.

Je n'aime pas ces options. N'y a-t-il pas une meilleure façon, plus propre? Je viens de chercher autour et j'ai trouvé System.Runtime.InteropServices.Marshal.GetHRForException. Est-ce que cela retournera un uint comme 0x80070021?

+3

> réflexion privée - ne veux pas faire ça. Perf va puer. - La perfusion d'exception pue quand même, donc je ne m'inquiéterais pas de l'aspect perf. La réflexion nécessite cependant FullTrust, est moche, et n'est pas supportée et sujette à la casse - ce qui est la raison pour laquelle vous ne devriez pas le faire. –

Répondre

54

NET Framework 4.5 et au-dessus, vous pouvez utiliser la propriété Exception.HResult:

int hr = ex.HResult; 

Pour les anciennes versions, vous pouvez utiliser Marshal.GetHRForException pour récupérer le HResult, mais has significant side-effects and is not recommended:

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

Merci beaucoup! Cela facilite vraiment le développement en cas d'interopérabilité C#/COM. – rds

+2

+1 Eww, nécessite une confiance totale ... Mais c'est quand même une solution. – reSPAWNed

+3

Méfiez-vous des effets secondaires: "Notez que la méthode ** GetHRForException ** définit le ** IErrorInfo ** du thread en cours, ce qui peut entraîner des résultats inattendus pour des méthodes telles que les méthodes ** ThrowExceptionForHR ** qui utilisent par défaut le ** IErrorInfo ** du thread en cours s'il est défini. " – HugoRune

0

Est-ce que CanRead propriété Aider dans ce cas?
dire appeler CanRead, si cela retourne vrai, appelez Read()

+0

Non, CanRead est vrai. Je crois que 80070021 est une erreur transitoire. Si je lis correctement le document, pour le manipuler, il est recommandé d'attendre un peu et de réessayer. – Cheeso

+0

Est-il possible que vous ayez ouvert le fichier à lire et que quelqu'un d'autre l'ait ouvert (en utilisant FileShare.Read), le 1er appelant ne peut plus le lire? Est-ce ce que vous voulez dire par transitoire? – shahkalpesh

+0

Non, ce que je veux dire est, un autre processus a appelé FileLock ou FileLockEx (http://msdn.microsoft.com/en-us/library/aa365203.aspx) sur le fichier pour verrouiller une plage dans le fichier. Ceci est parfois appelé un verrou d'octet. À un moment donné, le processus de verrouillage libérera le verrouillage de la gamme. C'est ce que je veux dire par "Transitoire". – Cheeso

0

Avez-vous profilées ces deux cas? J'imagine que la méthode de réflexion n'est pas si lente, surtout par rapport à tous les autres travaux que votre application va faire et à quelle fréquence cette exception est susceptible de se produire.

S'il s'avère qu'il y a un goulot d'étranglement, vous pouvez envisager de mettre en cache certaines des opérations de réflexion ou de générer une IL dynamique pour récupérer la propriété.

11

Pour ce que cela vaut, System.Exception.HResult n'est plus protégé dans .NET 4.5 - seul le setter est protégé. Cela n'aide pas avec le code qui pourrait être compilé avec plus d'une version de l'infrastructure.

3

Vous pouvez également utiliser l'interface 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"); 
    } 
} 
Questions connexes