I import many parts from different assemblies into my class like this:
[ImportMany(typeof(IServiceProvider))]
private IEnumerable<Lazy<IServiceProvider, IDictionary<string, object>>> ServiceProviders
{
get;
set;
}
After parts imported, Service providers are created on demand:
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;
}
As I commented in above code, many threads try to get value
of the lazy
variable (create new instance of it, if not created yet) at the same time.
Lazy<T>
has a constructor which allow to create instance (value
) in a thread-safe
manner, like this:
// 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
take cares of object creation when importing parts and I want to use the Lazy
constructor which allows for thread-safe value
creation but I don't know how.
When creating your CompositionContainer
, pass isThreadSafe=true
to the constructor.
Note that it's not safe to do any recomposition in a thread-safe container, so you shouldn't use catalogs that change, or CompositionBatch
, or the AttributedModelServices.ComposeParts()
extension method.