MSDN 说 System.Windows.Application 的公共(public)静态成员是线程安全的。但是当我尝试使用多线程运行我的应用程序时,出现以下异常:
ArgumentException: An entry with the same key already exists.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value)
at System.IO.Packaging.Package.AddIfNoPrefixCollisionDetected(ValidatedPartUri partUri,
PackagePart part)
at System.IO.Packaging.Package.GetPartHelper(Uri partUri)
at System.IO.Packaging.Package.GetPart(Uri partUri)
at System.Windows.Application.GetResourceOrContentPart(Uri uri)
at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean
bSkipJournaledProperties)
at System.Windows.Application.LoadComponent(Uri resourceLocator)
异常发生在以下调用中:
genericResources = (ResourceDictionary)Application.LoadComponent(new Uri("/Themes/Generic.xaml", UriKind.Relative));
该应用程序在单个线程上运行良好,甚至在两个或三个线程上也能正常运行。当我起床超过 5 点时,我每次都会收到错误消息。难道我做错了什么?我该怎么做才能解决这个问题?
最佳答案
你没有做错什么。 MSDN 是错误的。 Application.LoadComponent 实际上不是线程安全的。在我看来,这是 WPF 中的一个错误。
问题是每当 Application.LoadComponent 从“包”加载“部分”时:
- 检查包的内部缓存以查看该部分是否已加载,如果找到则返回
- 从文件中加载部分
- 将其添加到内部缓存
- 归还它
您有两个线程调用 Application.LoadComponent
以同时加载同一部分。 MSDN 文档说这没问题,但实际情况是:
- 线程 #1 检查缓存并开始从文件加载
- 线程 #2 检查缓存并开始从文件加载
- 线程 #1 完成从文件加载并添加到缓存
- 线程#2 完成从文件加载并尝试添加到缓存,导致重复键异常
该错误的解决方法是将所有对 Application.LoadComponent 的调用包装在一个 lock() 中。
您的锁对象可以在您的 App.cs 或其他地方(您的选择)中创建:
public static object MyLoadComponentLock = new Object();
然后您的 LoadComponent 调用如下所示:
lock(App.MyLoadComponentLock)
genericDictionary = (ResourceDictionary)Application.LoadComponent(...
关于c# - Application.LoadComponent 的线程错误( key 已存在),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2463822/