0

私は2009年からのこれらの質問を見ていました: C# Events and Thread Safety

同じトピックに関する Eric Lippert のブログ投稿も見ました

問題は要約すると、マルチスレッド環境では、別のスレッドがスレッド (スレッド A) の 'if' ステートメントと 'call delegate' ステートメントの間でデリゲートを登録解除する状況に遭遇することがあります。

私が読んでいたとき、この質問が頭に浮かびました:代替が競合状態またはスローされた例外のいずれかの選択であると思われる場合、それを try/catch ブロックでラップして、どちらも心配しないのはなぜですか? nullReferenceException をキャッチした場合は、catch ブロックでそれを無視して (単に例外を抑制するため)、先に進みます。

さて、Eric Lippert と John Skeet が C#、マルチスレッド、およびデリゲートについて少し知っていることは理解しています。

4

4 に答える 4

2

この種の例外の飲み込みに関する主な問題はNullReferenceException、イベントデリゲートがであることが原因であるかどうかを確認できないことnullです。デリゲート自体の中からスローされた可能性があります。

念のために言っておきますが、これを行う代わりに、あなたが言っていることは次のとおりです。

Action temp = Foo;
if (temp != null)
      temp();

これをする:

try {
    Foo();
}
catch (NullReferenceException e)
{
    // magically ignore it
}

繰り返しになりますが、このFoo()呼び出しは多くの理由で同様の例外を引き起こす可能性があり、無関係な例外をマスクすることになります。

于 2013-01-08T22:49:47.853 に答える
2

一般的に、例外がスローされた場合、それは何か問題が発生していることを意味します。

キャッチと例外は、間違いをなくすことはありません。操作はまだ失敗しました。それがするのは、間違っていることが起こっていることに対応する機会を与えることだけです。

于 2013-01-08T22:51:28.063 に答える
2

代替が競合状態またはスローされた例外のいずれかの選択であると思われる場合

それが記事のポイントではないと思います。

Eric が指摘するように、2 つの問題があります。

  1. デリゲートはnullの可能性があります
  2. ハンドラー自体が競合状態の影響を受ける可能性があります。登録解除コードが似event -= handler; DisposeRequiredResources();ているからといって、dispose が呼び出された後にハンドラー コードが実行されないわけではありません。

問題 1 は、通常、一時変数で解決されます。(必須ですがif (Foo != null) Foo();、競合状態のため機能しません)。他の解決方法には、空のデリゲートで初期化することが含まれます。ここで try/catch を使用すると、入力が増えるだけでなく、イベント ハンドラーで実際の NullReferenceExceptions を飲み込む危険性もあります。

問題 2 は、ハンドラーを堅牢にすることで解決されます。呼び出し全体を try/catch ブロックに入れても、問題は軽減されません。

于 2013-01-08T23:00:03.813 に答える
1

間違っていると理解しているかもしれませんが、try-catchだけですべての競合状態をキャッチすることはできません。以下のコードを参照してください

int count = 0;
for (int i = 0; i < 1000; i++) 
            Task.Factory.StartNew(()=>count++,TaskCreationOptions.LongRunning);
Console.WriteLine(count);

これは、数回実行すると1000以外を出力する場合があります。

于 2013-01-08T22:53:28.720 に答える