在 MEF2 中创建单例实例
Create Singleton instance in MEF2
我正在使用 MEF2 (Microsoft.Composition) 创建一个包含多个插件的应用程序。这些插件应该导入一些公共对象,并且它们都应该共享该对象的同一个实例……所以一个典型的单例。
但是,当我 [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):
经过反复试验,我似乎终于找到了解决办法。
技巧似乎是使用 ConventionBuilder
。这有一个名为 .Shared()
的扩展方法,它使从特定类型派生的所有对象都成为单例。
对于我的代码示例,只需将以下内容添加到启动代码的顶部:
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
我正在使用 MEF2 (Microsoft.Composition) 创建一个包含多个插件的应用程序。这些插件应该导入一些公共对象,并且它们都应该共享该对象的同一个实例……所以一个典型的单例。
但是,当我 [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):
经过反复试验,我似乎终于找到了解决办法。
技巧似乎是使用 ConventionBuilder
。这有一个名为 .Shared()
的扩展方法,它使从特定类型派生的所有对象都成为单例。
对于我的代码示例,只需将以下内容添加到启动代码的顶部:
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