2

このタイプの例外の原因となっている正確なコレクションが実際には特定されていないことがよくあります。それは本当ですか、それとも明白なはずですか?おそらく、例外メッセージを正しく解釈する方法がわかりません。

具体的にはこれについて疑問に思います。それが参照するコレクションは何ですか?

イベントデリゲートのパラメーターは単純に(オブジェクト送信者)であり、発生したイベントはnullパラメーターを渡します。イベントを発生させるクラス自体はリストを継承しますが、次のようになります。

public class TimeSerie : List<BarData>

ここで、「コレクション」がイベントを発生させるオブジェクトを指しているのか、それとも別のオブジェクトであるのかは明らかですか?たとえば、動的に変更されているメソッドのイベントハンドラーのコレクションである可能性がありますか?それとも、別の例外が発生しますか?

    ************** Exception Text **************
System.InvalidOperationException: 
Collection was modified; enumeration operation may not execute.
   at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
   at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
   at System.Windows.Forms.Control.Invoke(Delegate method)
   at SomeNameSpace.SomeUserControl.InvokeOnUpdateHistory(Object sender) in D:\SomePath\SomeUserControl.cs:line 5179
   at OtherNameSpace.OtherClass.TimeSerie.HistoryUpdateEventHandler.Invoke(Object sender)

UserControlで例外が発生します:

    public class SomeUserControl 

    private void InvokeOnUpdate(object sender)
    {
    this.Invoke(new GenericInvoker(Method));   // << Exception here!
    }

    private void Method() {...}

編集: いくつかのコードを追加しました。少し単純化されていますが、関連するビットが含まれていると思います。

private void Method() 
{
            if (this.instrument == null) return;  
            UnRegisterTimeSerieHandlers(this.ts);

            this.ts = instrument.DataSeries.GetTimeSerieByInterval(interval);
            if (ts != null)
            { 
                RegisterTimeseriesHandlers(ts);
                ClearAndLoadAllHistory();
            }
}

    private void UnRegisterTimeSerieHandlers(TimeSerie ts)
    {
        if (ts != null)
        {
            ts.TickUpdate -= InvokeUpdateCurrentBar;
            ts.NewBarUpdate -= InvokeUpdateNewBar;
            ts.HistoryUpdate -= InvokeOnUpdateHistory;
            this.ts = null;
        }
    }

    private void RegisterTimeseriesHandlers(TimeSerie ts)
    {
        ts.TickUpdate += InvokeUpdateCurrentBar;
        ts.NewBarUpdate += InvokeUpdateNewBar;
        ts.HistoryUpdate += InvokeOnUpdateHistory;
    }
4

2 に答える 2

5

はい、Control.Invoke()を使用すると、例外の原因を診断するのが非常に難しい場合があります。問題は、UIスレッドで発生したときに例外をキャッチし、ワーカースレッドで再スローすることです。必然的に、ワーカースレッドは、Invoke()の戻り値が使用できないことを知る必要があります。避けられない副作用は、それがどこで爆発し、どのようにそこに到達したかを示す聖なるスタックトレースを失うことです。

デバッガーが接続されているときに問題を再現できる場合は、[デバッグ+例外]を使用し、[CLR例外]の[スロー]チェックボックスをオンにします。例外がスローされるとデバッガーが停止し、適切なステートメントの場所と呼び出しスタックを確認できます。

そうでない場合は、代わりにControl.BeginInvoke()の使用を検討してください。これはファイアアンドフォーゲットバージョンのInvoke()であるため、呼び出されたメソッドがスローされると、その例外がUIスレッドで発生し、正確なスタックトレースが取得されます。

一般に、BeginInvoke()を常に優先する必要があります。ワーカースレッドが停止することはなく、多くのデッドロックシナリオを回避し、適切な例外フィードバックを提供します。Invoke()の使用は一般的に間違いです。

于 2013-01-23T00:47:11.777 に答える
0

タイマーを使用しているようです。呼び出しを使用せずに、タイマーコールバック(別のスレッド)からコレクション(コレクションはUI要素のプロパティである可能性が高い)を変更している可能性がありControl.Invoke()ますか?

于 2013-01-22T23:59:58.863 に答える