web-dev-qa-db-ja.com

コンストラクターからカスタム例外クラスのInnerExceptionを設定する方法

オブジェクトのコンストラクターにいるときに、InnerExceptionオブジェクトのExceptionプロパティを設定するにはどうすればよいですか?つまり、セッターを持たないプロパティのバッキングフィールドを見つけて設定することになります。

ところで、私はこれを見ました evain.net-Reflectionを使用してプロパティをバッキングするフィールドを取得する ですが、可能であれば、非ILベースのソリューションを探しています。

ExceptionのコンストラクターはExceptionタイプが作成される場所なので、基本クラスコンストラクターMyException() :base(...)などを使用して呼び出すことはできません。

44
_NT

なぜInnerExceptionをパラメータとしてコンストラクタを呼び出せないのですか?何らかの理由でそれが不可能な場合、System.Exceptionのバッキングフィールドは次のようになります。

private Exception _innerException;

Redgateのリフレクター を使用してそれを見つけました。リフレクションを使用すると、内部例外を設定できると思います。

編集:ほとんどの場合、リフレクションを介してプライベートフィールドにアクセスすることはお勧めできませんが、NTのケースについて十分に知らないため、それは良いか悪い考えです。

14
Meta-Knight

基本のctorを呼び出して、内部例外を設定します。

public MyException(string message, Exception innerException)
       : base(message, innerException) {...}

例外を取得するためにコードを実行する必要がある場合は、静的メソッドを使用します。

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...}
static Exception GetInner(SomeData data) {...} // <===== your type creation here!
static string GetMessage(SomeData data) {...}
85
Marc Gravell

Exceptionクラスには、内部例外をパラメーターとして受け入れるオーバーロードされたコンストラクターがあります。

Exception exc = new Exception("message", new Exception("inner message"));

これはあなたが探しているものですか?

44
Paolo Tedesco
Exception exceptionWithMoreInfo = new Exception("extra info", ex);

バブルが発生する前に情報を追加したい例外をトラップしたと想定すると、通常の方法になります。

8
dove

私があなたの質問を理解したら、あなたはこのようなことをしたいです:

Exception ex = new Exception("test");
Exception innerEx = new Exception("inner");
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx);

Exceptionから継承するオブジェクトのコンストラクターにいる場合は、最初のthisの代わりにexを使用します。

ただし、これは、処理しようとしているものを処理するための最良の方法ではない場合があります。

2
pauloya

Redgateのリフレクターを使用してフィールドを見つけます。例外の実装が変わることはないと思います...しかし、それはリスクです!

1
NT_

Exception(string, Exception)コンストラクターを使用する場合、InnerExceptionを設定する必要はありませんか?これを変更できないのは設計上の理由によると思いますが、構築時には常に適切なコンストラクターに従うことができます。

class MyException : Exception {
    public MyException()
        : base("foo", new Exception("bar"))
    {
        ...
    }

    ...
}

私はコードの例外チェーンを壊すべきではないと思います。これは通常、二度と見つからないエラーにつながるからです。

1
Joey

私の状況では、このコードを使用しました:

class Foo 
{
    void Bar(MyException myException = null)
    {
        try
        {
            SomeActions.Invoke();
        }
        catch (Exception ex)
        {
            if (myException != null)
            {
                // Here I regenerate my exception with a new InnerException
                var regenMyException = (MyException)System.Activator.CreateInstance(myException.GetType(), myException.Message, ex);
                throw regenMyException;
            }

            throw new FooBarException("Exception on Foo.Bar()", ex);
        }
    }
}

HTH誰か;).

0
shA.t

私は本当にパーティーに遅れていることを知っていますが、これはうまくいくことがわかりました。

public class MyException: Exception
{
    public void SetInnerException(Exception exception) 
    {
        typeof(Exception)
            .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
            .SetValue(this, exception);
    } 
}

コツは、実際のExceptionタイプの_innerExceptionフィールドを取得してから、内部例外値をクラスインスタンス(この場合はMyException)に設定することです。

これは変数に対しても機能します。

Exception mainException = new Exception();
typeof(Exception)
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
    .SetValue(mainException , new Exception("Something bad happened!"));
0
user2278642