0

メッセージハンドラーに次のコードがあります(任意のスレッドで呼び出すことができます):

private readonly Dictionary<string,IView> _openedViews = new Dictionary<string,IView>();
private readonly object _lockObject = new object();

public MainView() 
{
    Messenger.Default.Register<ViewChangeMessage>(this, "adminView", m =>
    {
         var key = m.ViewName;
         lock (_lockObject)
         {
            if (_openedViews.ContainsKey(key) == false)
                _openedViews.Add(key, GetView(key));
           content.Content = _openedViews[key];
         }
         //...
    });
    //...

どうすればこの例外を取得できますか:An element with the same key already exists in the System.Collections.Generic.Dictionary<TKey,TValue>.

メッセージを複数回すばやく送信すると、例外が発生します。

編集: コードにコンテキストを追加しましたMessenger。Galasoft.MVVMLight からのものです。

4

4 に答える 4

1

あなたが投稿したそのコードでは、データ競合は見られません。

GetViewデータ競合を引き起こすことができない場合は、ロックされたコードのブロック全体をConcurrentDictionary.GetOrAddに置き換えることができます。

private readonly ConcurrentDictionary<string,IView> _openedViews = 
          new ConcurrentDictionary<string,IView>();

public MainView() 
{
    Messenger.Default.Register<ViewChangeMessage>(this, "adminView", m =>
    {
         var key = m.ViewName;
         content.Content = _openedViews.GetOrAdd(key, GetView(key));
         //...
    });
    //...
于 2012-06-13T07:43:19.103 に答える
0

Move var key = m.ViewName; inside lock statement.

于 2012-06-13T08:59:13.420 に答える
0

何が起こったのか: GetView はビューをインスタンス化し、それはどこかで実行時間の長い操作 (バックグラウンド スレッドで待機中) を持っていたので、待機中に UI がロックされないように、誰かがこのコードを導入しました:

public static void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}

そして、PushFrame のおかげで、2 番目のメッセージが最初のメッセージと同じスレッドで処理されたため、ロックはそれを止めるために何もしませんでした。
コードをこれに再配置すると、問題はなくなりました。

if (_openedViews.ContainsKey(key) == false)
{
   _openedViews.Add(key, null);
   _openedViews[key] = ServiceRegistry.GetService<IShellService>().GetView(key);
}
于 2012-06-13T13:19:08.970 に答える
0

すべてのスレッドが lockObject の同じインスタンスを使用していることを確認しましたか? そうでない場合、複数のスレッドが追加コードに到達するのを止めることはありません。

于 2012-06-13T07:11:56.320 に答える