6

コンストラクターで仮想メンバーを呼び出す効果をテストしていたところ、そのメンバーを呼び出すと、結果の例外がTargetInvocationException.

ドキュメントによると、これは次のとおりです。

リフレクションによって呼び出されたメソッドによってスローされる例外

ただし、リフレクションによる呼び出しは認識していません。これは、仮想メンバーが常にリフレクションを介して呼び出されることを意味しますか? そうでない場合、この場合はなぜそうなのですか?

コード:

class ClassA
    {
        public ClassA()
        {
            SplitTheWords();
        }

        public virtual void SplitTheWords()
        {
            //I've been overidden
        }
    }

class ClassB : ClassA
    {
        private readonly String _output;

        public ClassB()
        {
            _output = "Constructor has occured";
        }

        public override void SplitTheWords()
        {
            String[] something = _output.Split(new[]{' '}); //TargetInvocationException!
        }
    }
4

2 に答える 2

5

いいえ、仮想メソッドはvirtual dispatch経由で呼び出されます。

ここではリフレクションは使用されていません。また、仮想メソッド呼び出しでもありません。このタイプの例外はリフレクションを介して呼び出されたメソッドによってスローされるという点で、例外のドキュメントは少し誤解を招くと思いますが、それだけではありません。

問題のコードで例外が発生する理由に興味がある人は、コンストラクターが実行される順序が原因です。ClassBコンストラクターは次と同じです。

public ClassB() : base()
{
    _output = "Constructor has occured";
}

への呼び出しに注意してくださいbase()。これは、ClassBコンストラクターが実行される前、つまり_output が割り当てられる前に基本コンストラクターを呼び出します。SplitTheWords仮想メソッドは基本コンストラクターで呼び出され、 に解決されますClassB.SplitTheWords。このメソッドは を使用しようとする_outputため、エラーが発生します。

コンストラクターから仮想メソッドを呼び出すべきではない理由の詳細については、この SO の質問に役立つ情報がいくつかあります。Eric Lippert は、なぜこれがここに当てはまるのかについて、非常に優れたブログ投稿も行っています。

于 2012-07-04T13:46:17.740 に答える
0

仮想メンバーはリフレクションを介して呼び出されますか (通常の状況で)?

番号。

コンストラクターからでもないので、何か他のことが起こっています。表示したコードを呼び出しているコードと、例外からのスタック トレースを確認すると役立ちます。

于 2012-07-04T13:46:02.173 に答える