Использование 'System.Lazy.LazyThreadSafetyMode' с MEF - PullRequest
2 голосов
/ 29 декабря 2010

Я импортирую множество деталей из разных сборок в свой класс, например:

[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 ]

2 голосов
/ 29 декабря 2010

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

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

1 голос
/ 29 декабря 2010

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

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

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