C# 4.0 如何扩展MEF以基于作为属性提供的工厂类型创建对象?
考虑以下用于组合C# 4.0 如何扩展MEF以基于作为属性提供的工厂类型创建对象?,c#-4.0,mef,C# 4.0,Mef,考虑以下用于组合使用者的现有类 public interface IProducer { void Produce(); } [Export(typeof(IProducer))] public class Producer : IProducer { public Producer() { // perform some initialization } public void Produce() { // p
使用者的现有类
public interface IProducer
{
void Produce();
}
[Export(typeof(IProducer))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
public class Consumer
{
[Import]
public IProducer Producer
{
get;
set;
}
[ImportingConstructor]
public Consumer(IProducer producer)
{
Producer = producer;
}
public void DoSomething()
{
// do something
Producer.Produce();
}
}
但是,Producer
的创建已经变得非常复杂,无法在构造函数中完成,默认行为也不再足够
我想介绍一个工厂,并使用producer本身上的自定义FactoryAttribute对其进行注册。这就是我的想法:
[Export(typeof(IProducer))]
[Factory(typeof(ProducerFactory))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
[Export]
public class ProducerFactory
{
public Producer Create()
{
// Perform complex initialization
return new Producer();
}
}
public class FactoryAttribute : Attribute
{
public Type ObjectType
{
get;
private set;
}
public FactoryAttribute(Type objectType)
{
ObjectType = objectType;
}
}
如果我必须自己编写“新”代码,它很可能如下所示。它将使用factory属性(如果存在)来创建零件,或者默认使用MEF来创建零件
public object Create(Type partType, CompositionContainer container)
{
var attribute = (FactoryAttribute)partType.GetCustomAttributes(typeof (FactoryAttribute), true).FirstOrDefault();
if (attribute == null)
{
var result = container.GetExports(partType, null, null).First();
return result.Value;
}
else
{
var factoryExport = container.GetExports(attribute.ObjectType, null, null).First();
var factory = factoryExport.Value;
var method = factory.GetType().GetMethod("Create");
var result = method.Invoke(factory, new object[0]);
container.ComposeParts(result);
return result;
}
}
有许多文章介绍如何实现ExportProvider,包括:
然而,这些例子并不理想
Producer
,也不了解IProducer
。创建CompositionContainer
时,它将无法注册工厂Producer
被多个应用程序重用,开发人员在创建CompositionContainer
时可能会错误地忘记注册工厂CompositionContainer
时,记住注册工厂可能会带来维护噩梦李>
我开始创建一个ExportProvider(假设这将提供使用factory实现构造的方法)
公共类FactoryExportProvider:ExportProvider
{
受保护的覆盖IEnumerable GetExportsCore(导入定义,
原子组成(原子组成)
{
//在这里做什么?
}
}
但是,我很难理解如何告诉MEF使用FactoryAttribute中定义的factory对象,如果不存在这样的属性,则使用默认的创建机制
正确的实施方式是什么?我正在使用和.NET 4。您可以使用属性导出:
public class ProducerExporter
{
[Export]
public IProducer MyProducer
{
get
{
var producer = new Producer();
// complex initialization here
return producer;
}
}
}
public class ProducerFactory
{
[Export(typeof(Func<Type1,Type2,IProducer>)]
public IProducer CreateProducer(Type1 arg1, Type2 arg2)
{
return new Producer(arg1, arg2);
}
}
请注意,术语工厂并不适用于您的示例,我将保留该术语用于进口商希望随意创建实例(可能通过提供一个或多个参数)的情况。这可以通过导出方法来实现:
public class ProducerExporter
{
[Export]
public IProducer MyProducer
{
get
{
var producer = new Producer();
// complex initialization here
return producer;
}
}
}
public class ProducerFactory
{
[Export(typeof(Func<Type1,Type2,IProducer>)]
public IProducer CreateProducer(Type1 arg1, Type2 arg2)
{
return new Producer(arg1, arg2);
}
}
公共类生产工厂
{
[导出(类型)(功能)]
公共IProducer CreateProducer(类型1 arg1,类型2 arg2)
{
返回新的生产者(arg1、arg2);
}
}
在导入端,您将导入一个
Func
,您可以随意调用它来创建新实例。术语工厂在我的示例中是合适的,因为我遵循的.MEF将是“客户机”创建对象的工厂。问题是如何扩展MEF以使用此模式。这两种技术都是可行的,但提出了一个问题:谁负责管理正在创建的IProducer的生命周期。出于维护的原因,我会避免两者。@WernerStrydom:1)关于生命周期:在我的第一个建议中,MEF负责一生。在第二个建议中,您可以让func创建ExportLifetime
,这样导入程序就可以通过一个实例发出完成的信号。这就是MEF中现有的ExportFactory
机制的工作原理。2) 我不确定你所说的“维护原因”是什么意思。您考虑的解决方案仍然需要为容器设置一个特殊的导出提供程序。我自己的建议不需要这样做。此外,我刚刚意识到,您可能不知道MEF的进口商(不是MEF本身)是客户,因此对“工厂”一词的混淆。解决方案是侵入性的。它要求我改变我所有的消费者。它打破了我在没有MEF的情况下观察物体时所做的每一个假设。当producerxporter.MyProducer返回一个对象时,谁拥有它,谁处置它?如果消费者调用ProducerFactory.CreateProducer,谁拥有它,谁在处理它?如何实现重用?我想说的是,它确实很容易出错,大型代码库的维护人员(这是其中的一部分)可能会感到困惑,并做出错误的事情。@WernerStrydom:我认为您误解了属性导出解决方案。它的工作方式与使用者的类导出完全相同:它不需要对使用者进行任何更改(您只需导入IProducer
),所有权的工作方式相同(容器拥有对象,并在必要时对其进行处理)。