我在消息处理程序中有以下代码(可以在任何线程上调用):
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
答案 0 :(得分: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));
//...
});
//...
答案 1 :(得分:0)
您是否确保所有线程都使用相同的lockObject实例?如果他们不是那么它将不会阻止多个线程到达你的添加代码。
答案 2 :(得分:0)
在var key = m.ViewName;
语句中移动lock
。
答案 3 :(得分:0)
以下是发生的事情: GetView实例化了一个视图,它在某个地方有一个长时间运行的操作(在后台线程上等待),所以等待不会锁定用户介绍此代码的UI:
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
并且由于PushFrame,第二条消息在第一条消息上被处理,因此锁没有阻止它。
一旦我重新安排了代码,问题就消失了:
if (_openedViews.ContainsKey(key) == false)
{
_openedViews.Add(key, null);
_openedViews[key] = ServiceRegistry.GetService<IShellService>().GetView(key);
}