MEF组成问题,多线程

Qué*_*dre 7 .net c# multithreading mef thread-safety

我有以下代码:

public class Temp<T, TMetadata>
{
    [ImportMany]
    private IEnumerable<Lazy<T, TMetadata>> plugins;

    public Temp(string path)
    {
        AggregateCatalog aggregateCatalog = new AggregateCatalog();
        aggregateCatalog.Catalogs.Add(new DirectoryCatalog(path));
        CompositionContainer container = new CompositionContainer(aggregateCatalog);
        container.ComposeParts(this);
    }

    public T GetPlugin(Predicate<TMetadata> predicate)
    {
        Lazy<T, TMetadata> pluginInfo;

        try
        {
            pluginInfo = plugins.SingleOrDefault(p => predicate(p.Metadata));
        }
        catch
        {
            // throw some exception
        }

        if (pluginInfo == null)
        {
            // throw some exception
        }

        return Clone(pluginInfo.Value); // -> this produces errors
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个对象,TempGetPlugin()从多个线程调用.有时我会遇到奇怪的构图错误,我没有找到重现的方法.例如:

"System.InvalidOperationException: Stack empty.
    at System.Collections.Generic.Stack`1.Pop()
    at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(PartManager partManager, ComposablePart part, Boolean shouldTrackImports)
    at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(ComposablePart part)
    at System.ComponentModel.Composition.Hosting.CompositionServices.GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition)
    at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExportedValue(CatalogPart part, ExportDefinition export, Boolean isSharedPart)
    at System.ComponentModel.Composition.ExportServices.GetCastedExportedValue[T](Export export)
    at System.Lazy`1.CreateValue()
    at System.Lazy`1.LazyInitValue()
    at Temp`2.GetPlugin(Predicate`1 predicate)..."
Run Code Online (Sandbox Code Playgroud)

可能是什么原因以及如何解决此代码?

Adi*_*ter 20

CompositionContainer类有一个鲜为人知的构造,其接受一个isThreadSafe参数(默认为假出于性能的原因).如果您将此值设置为true来创建容器,我相信您的问题将得到解决:

CompositionContainer container = new CompositionContainer(aggregateCatalog, true);
Run Code Online (Sandbox Code Playgroud)

另外,与原始问题无关,而不是调用Clone()插件,您可以使用导出工厂 - 这样您就不必实现自己的克隆方法,因为MEF将为您创建一个新实例.