Ошибки Threading с Application.LoadComponent (ключ уже существует)

MSDN говорит, что публичные статические члены System.Windows.Application являются streamобезопасными. Но когда я пытаюсь запустить мое приложение с несколькими streamами, я получаю следующее исключение:

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)); 

Приложение работает отлично на одном streamе и даже на два или три. Когда я встаю через 5, я получаю ошибку каждый раз. Я делаю что-то неправильно? Что я могу сделать, чтобы исправить это?

Вы не делаете что-то неправильно. MSDN ошибочна. Application.LoadComponent на самом деле не является streamобезопасным. Это, по-моему, ошибка в WPF.

Проблема в том, что всякий раз, когда Application.LoadComponent загружает «Часть» из «Пакета», он:

  1. Проверяет свой внутренний кеш для пакета, чтобы узнать, загружена ли эта часть и возвращает ее, если найден
  2. Загружает деталь из файла
  3. Добавляет его во внутренний кеш
  4. Возвращает его

У вас есть два streamа, вызывающие Application.LoadComponent для загрузки одной и той же части одновременно. В документации MSDN говорится, что это нормально, но происходит следующее:

  1. Тема №1 проверяет кеш и начинает загрузку из файла
  2. Тема №2 проверяет кеш и начинает загрузку из файла
  3. Тема № 1 завершает загрузку из файла и добавляет в кеш
  4. Тема № 2 завершает загрузку из файла и пытается добавить в кеш, что приводит к дублированию ключевого исключения

Обходной путь для ошибки заключается в том, чтобы обернуть все вызовы Application.LoadComponent внутри lock ().

Ваш объект блокировки может быть создан таким образом в вашем App.cs или в другом месте (на ваш выбор):

  public static object MyLoadComponentLock = new Object(); 

Тогда ваш запрос LoadComponent выглядит следующим образом:

  lock(App.MyLoadComponentLock) genericDictionary = (ResourceDictionary)Application.LoadComponent(... 

Похоже, что элемент с тем же ключом уже добавлен на карту. Это не проблема с streamами, это проблема с вашей программой. Один stream добавил пару ключ / значение к карте, а второй stream пытается добавить значение с помощью идентичного ключа, как у вас в итоге были идентичные ключи на двух отдельных streamах? Как вы генерируете ключи?

Элементы объекта SortedList сортируются по ключам либо в соответствии с конкретной реализацией IComparer, указанной при создании SortedList, либо в соответствии с реализацией IComparable, предоставляемой самими ключами. В любом случае SortedList не позволяет дублировать ключи.

(из документации msdn)

Обновить:
Попробуйте синхронизировать, когда вы вызываете LoadComponent и посмотрите, сохраняется ли проблема.

Я просто не знаю, что они означают, когда говорят следующее:

Публичные статические (Shared in Visual Basic) члены этого типа являются streamобезопасными. Кроме того, методы FindResource и TryFindResource и свойства Properties и Resources являются streamобезопасными.

Он уверен, что это безопасный stream, но если он дублирует идентичные ключи, тогда они должны ссылаться на некоторые другие типы безопасности streamов.