2010-12-29 2 views
2

импортировать много деталей из различных сборок в моем классе, как это:Использование «System.Lazy.LazyThreadSafetyMode» с MEF

[ImportMany(typeof(IServiceProvider))] 
private IEnumerable<Lazy<IServiceProvider, IDictionary<string, object>>> ServiceProviders 
    { 
     get; 
     set; 
    } 

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

private IServiceProvider GetServiceProvider(String name) 
{ 
    foreach (var serviceProvider in ServiceProviders) 
    { 
     String currentName = (String)serviceProvider.Metadata["Name"]; 
     if (currentName == name) 
      return serviceProvider.Value; // Many threads receive here and try to create new instance. 
    } 

    return null; 
} 

Как я уже отмечал выше, многие потоки пытаются получить value переменной lazy (создайте новый экземпляр, если он еще не создан) в одно и то же время.

Lazy<T> имеет конструктор, который позволяет создать экземпляр (value) в thread-safe образом, как это:

// Something here... 
Dictionary<string, object> metadata = new Dictionary<string,object>(); 
metadata.Add("Name", "test"); 
Lazy<IServiceProvider, IDictionary<string, object>> serviceProvider = new Lazy<IServiceProvider, IDictionary<string, object>>(ServiceProviderValueFactory, metadata, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); 
// Now access to 'serviceProvider.Value' creates an instance (if not created yet) in a thread-safe manner. 

private IServiceProvider ServiceProviderValueFactory() 
{ 
    // Create and return a new instance of 'IServiceProvider'. 
} 

MEF, принимали заботы создания объекта при импорте деталей, и я хочу использовать Lazy конструктор, который позволяет для потокобезопасного создания value, но я не знаю как.

ответ

2

При создании CompositionContainer перейдите в конструктор isThreadSafe=true.

Обратите внимание, что небезопасно делать какие-либо перекомпоновки в потокобезопасном контейнере, поэтому вам не следует использовать изменяемые каталоги или CompositionBatch или метод расширения AttributedModelServices.ComposeParts().

+0

На самом деле мне нужно обновить 'DirectoryCatalog', чтобы добавить/удалить и заменить измененный плагины из контейнера. Это против безопасности потоков? – Xaqron

+0

@ Xaqron Да, это было бы против безопасности потоков. Если это серверное приложение, вероятно, лучше всего создать новый каталог и контейнер, которые будут использоваться для всех будущих запросов, и пусть текущий контейнер будет использоваться для завершения текущих запросов. Если это клиентское приложение, вам, вероятно, потребуется приостановить работу над любыми другими потоками, которые могут обращаться к контейнеру, прежде чем обновлять каталог. –

1

Я не уверен, что это то, что вы можете изменить. Тип Lazy<T, M> инициализируется внутренним классом ExportServices и не может быть переопределен. Если вы подклассифицировали ExportProvider, то цель GetExports или GetExportsCore, которые возвращают Lazy<T, M>, не являются абстрактными или виртуальными, поэтому их нельзя переопределить.

ExportServices В это закодировано как:

return new Lazy<T, M>(..., LazyThreadSafetyMode.PublicationOnly); 
+0

+1 для деталей я не знал. Хотя источник доступен на 'codeplex', я не собираюсь разворачивать свою версию. Новые библиотеки, такие как 'MEF' и' Lazy', имеют проблемы с параметризованными конструкторами и вызвали у меня много проблем. – Xaqron