C# · 12月 30, 2021

c# – 由MEF容器处理组件?

我使用MEF将接口映射到实现类作为DI的一种方式.例如,我使用导入属性作为接口,导出为实现类.我的理解是,MEF框架将创建实现类实例并将它们保存在MEF的容器中以供使用或自动注入.

我的一些实现类实现了IDispose接口.由于实例是由MEF创建的,我想我应该让MEF调用组件的Dispose方法,如果它们在MEF出来时是一次性的.例如,在我的申请中,我提到了MEF的容器.当应用程序终止时,我调用该容器的Dispose方法.问题是我的组件的Dispose从不被调用.

以下是有关导入和导出映射的示例代码:

[Import]private IMyInterface IComponent1 { get; set; }….[Export]private IMyInterface Component { get { var instance = new MyImpleMetation(); …. return instance; }}….

对于其他映射也有很多其他的导入和导出定义.我以这种方式构建映射,以便MEF了解关系以及如何创建映射实例的方式.以下是我的应用程序中使用AssemblyCatalog加载映射的一些代码:

var catalog = new AggregateCatalog();catalog.Add (new AssemblyCatalog(Assembly.GetExecutingAssembly());var batch = new CompositionBatch();batch.AddPart(catalog);// MEF container has all the mappingsvar container = new CompositionContainer(catalog);….// Get instance from containervar instance = container.GetExportedValue<IMyInterface>();// my instance CTOR has a contructor with several other // implementation instances injected by interface// instance starts to do its job and coordinates others …instance.Start();….// Finally the job is done.// Dispose the container explicitly there.container.Dispose();// But my components are never disposed// this results some connections not being closed// file streams not being closed…

这里的实例有许多其他组件通过CTOR通过MEF注入.这些组件还包含由MEF注入的其他组件.问题在于,由于某些实例被共享,因此很难决定何时配置组件.如果我打电话给Dispose,这将导致其他人无法使用它.如图所示,实例由MEF创建并注入到我的应用程序类中.每个组件不应该有其他知识,应该使用注入组件来完成这项工作.

我不知道在应用程序终止或容器处理时,我应该如何指示MEF在组件上调用Dispose?我应该在组件上调用Dispose吗?我认为这是正确的,因为MEF创建它们并将其注入客户端.客户在完成工作时不应该打电话给他们.

解决方法 MEF管理其创建的组件的使用寿命.看起来您的示例中的问题是您要处理的对象实际上不是由MEF创建的.也许你想做这样的事情: public class ComponentExporter : IDisposable{ private IMyInterface _component; [Export] public IMyInterface Component { get { if (_component != null) { _component = new MyImplementation(); // … } return _component; } } public void Dispose() { if (_component != null) { _component.Dispose(); } }}

ComponentExporter是由MEF实际创建的类,如果它实现了IDisposable,则MEF将使用该容器进行处理.在此示例中,ComponentExporter在处理时处理已创建的组件,这很可能是您想要的.

当然,如果您直接将导出导出到MyImplementation类,那将会更容易.我假设你有一些理由不这样做,但这是它的外观:

[Export(typeof(IMyInterface))]public class MyImplementation : IMyInterface,IDisposable{ // …}

关于代码的其他一些注意事项:您可能不需要通过批处理将目录添加到容器中,除非您将其导入到某个位置并从容器内的部分进行修改.而且,如果您正在处理许多请求并且关心性能,那么您只应该创建一次AssemblyCatalog,然后对所有请求使用相同的请求.