web-dev-qa-db-ja.com

System.IO.IOExceptionのHResultを確認するにはどうすればよいですか?

System.Exception.HResultプロパティは保護されています。リフレクションやその他の醜いハックに頼ることなく、例外の内部を覗いてHResultを取得するにはどうすればよいですか?


状況は次のとおりです。
システム上のファイルを開いて読み取るバックアップツールを作成したいと思います。 このガイダンス に従って、FileAccess.ReadとFileShare.ReadWriteを使用してファイルを開きます。これは、ファイルを読み取ったときにファイルが書き込み用に開いているかどうかを気にしないためです。

場合によっては、読み取っているファイルが別のアプリによって開かれていると、System.IO.FileStream.Read()メソッドがSystem.IO.IOExceptionをスローします。「別のプロセスがファイルの一部をロックしているため、プロセスはファイルにアクセスできません。ファイル"。これは エラー 、またはHResult0x80070021だと思います。 [[〜#〜] edit [〜#〜]:別のプロセスが LockFileEx を呼び出したときにこれを返すことができると思いますファイル内のバイト範囲をロックします。]

このエラーが発生したら、一時停止して再試行したいと思います。これがここでとるべき適切な行動だと思います。ロックプロセスがバイト範囲ロックをすばやく解放する場合は、ファイルの読み取りを続行できます。

この理由でIOExceptionを他の理由と区別するにはどうすればよいですか?私はこれらの方法を考えることができます:

  • 個人的な反省-それをしたくない。パフォーマンスは悪臭を放ちます。
  • exception.ToString()を呼び出して、文字列を解析します。ハッキーな感じ。 i18nバージョンでは機能しません。

私はこれらのオプションが好きではありません。より良い、よりクリーンな方法はありませんか?


探し回ったところ、 System.Runtime.InteropServices.Marshal.GetHRForException が見つかりました。それは0x80070021のようなuintを返しますか?

35
Cheeso

.Net Framework 4.5以降の場合、Exception.HResultプロパティを使用できます。

int hr = ex.HResult;

古いバージョンの場合、 Marshal.GetHRForException を使用してHResultを取り戻すことができますが、これ 重大な副作用があり、推奨されません

int hr = Marshal.GetHRForException(ex);
56
JaredPar

その価値については、System.Exception.HResultは.NET4.5では保護されなくなりました-セッターのみが保護されます。これは、フレームワークの複数のバージョンでコンパイルされる可能性のあるコードには役立ちません。

11
UweBaemayr

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

この場合、CanReadプロパティは役に立ちますか?
つまりCanReadを呼び出し、それがtrueを返す場合は、Read()を呼び出します。

0
shahkalpesh

これらのケースのいずれかをプロファイリングしましたか?リフレクションメソッドは、特にアプリが実行する他のすべての作業と比較して、それほど遅くはなく、この例外が発生する可能性が高いと思います。

ボトルネックであることが判明した場合は、リフレクション操作の一部をキャッシュするか、動的ILを生成してプロパティを取得することを検討できます。

0
Kevin Pullin

ネクロマンシング。
または、リフレクションによって保護されたプロパティをフェッチすることもできます。

private static int GetHresult(System.Exception exception)
{
    int retValue = -666;

    try
    {
        System.Reflection.PropertyInfo piHR = typeof(System.Exception).GetProperty("HResult", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);

        if (piHR != null)
        {
            object o = piHR.GetValue(exception, null);
            retValue = System.Convert.ToInt32(o);
        }
    }
    catch (Exception ex)
    {
    }

    return retValue;
}
0
Stefan Steiger