1

我正在使用 MEF2 (Microsoft.Composition) 创建具有多个插件的应用程序。这些插件应该导入一些通用对象,并且它们都应该共享该对象的同一个实例……所以是典型的 Singleton。

但是,当我[Import]将这个通用对象放入我的插件时,它们都会获得自己的副本而不是共享的副本。

在 .NET Framework MEF1 中,所有对象默认创建为单例。.NET Core MEF2 似乎并非如此。

如何确保我的所有插件都获得我的公共对象的相同单例实例?

示例代码

启动

static void Main(string[] args) {
    ContainerConfiguration containerConfig = new ContainerConfiguration()
        .WithAssembly(Assembly.GetExecutingAssembly())
        .WithAssembly(typeof(ICommonObject).Assembly);

    using (CompositionHost container = containerConfig.CreateContainer())             {
        _mainApp = container.GetExport<MainApp>();
        _mainApp.Start();
    }
}

主应用

[Export(typeof(MainApp))]
public class MainApp {
    [Import] public ICommonObject CommonObject { get; set; }
    [ImportMany] public IEnumerable<IPlugin> Plugins { get; set; }

    public void Start() {
        CommonObject.SomeValue = "foo";
        Console.WriteLine("SomeValue (from MainApp): " + CommonObject.SomeValue);

        foreach (IPlugin plugin in Plugins) {
            plugin.Start();
        }
    }
}

插入

[Export(typeof(IPlugin))]
public class SomePlugin : IPlugin {

    [Import] public ICommonObject CommonObject { get; set; }

    public void Start() {
        Console.WriteLine("SomeValue (from plugin): " + CommonObject.SomeValue);
    }
}

输出

SomeValue (from MainApp): foo
SomeValue (from plugin):
4

1 回答 1

2

经过多次反复试验,我似乎终于自己找到了解决方案。

诀窍似乎是使用ConventionBuilder. 这有一个名为的扩展方法.Shared(),它使从特定类型派生的所有对象都变成单例。

对于我的代码示例,只需将以下内容添加到 Startup 代码的顶部:

ConventionBuilder conventions = new ConventionBuilder();
conventions.ForTypesDerivedFrom<ICommonObject>()
    .Export<ICommonObject>()
    .Shared();

ContainerConfiguration containerConfig = new ContainerConfiguration()
    .WithAssembly(Assembly.GetExecutingAssembly(), conventions);

出于某种原因,实现的对象ICommonObject甚至不需要[Export]属性。无论如何,该示例的输出现在是:

SomeValue (from MainApp): foo
SomeValue (from plugin): foo
于 2018-08-29T21:01:02.880 回答