如何根据作为属性提供的工厂类型扩展MEF以创建对象?

时间:2012-04-30 00:23:09

标签: c#-4.0 mef

考虑以下使用MEF撰写Consumer的现有类。

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的创建变得非常复杂,以至于无法在构造函数中完成,并且默认行为不再足够。

我想介绍一个工厂并使用生产者本身的自定义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;
    }
}

如果我必须写" new"代码自己,它可能看起来如下。它将使用工厂属性(如果存在)来创建零件,或者默认使用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,包括:

  1. MEF + Object Factories using Export Provider
  2. Dynamic Instantiation
  3. 然而,当

    时,这些例子并不理想
    1. 该应用程序没有Producer的依赖关系或知识,只有IProducer。创建CompositionContainer时,无法注册工厂。
    2. Producer被多个应用程序重用,开发人员可能会错误地忘记在创建CompositionContainer时注册工厂。
    3. 有许多类型需要自定义工厂,并且在创建CompositionContainer时记住注册工厂可能会造成维护噩梦。
    4. 我开始创建一个ExportProvider(假设这将提供使用工厂实现构造的方法)。

      public class FactoryExportProvider : ExportProvider
      {
          protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
                                                                AtomicComposition atomicComposition)
          {
              // What to do here? 
          }
      }
      

      但是,我无法理解如何告诉MEF使用FactoryAttribute中定义的工厂对象,如果不存在这样的属性,则使用默认的创建机制。

      实施此方法的正确方法是什么?我正在使用MEF 2 Preview 5和.NET 4。

1 个答案:

答案 0 :(得分:3)

您可以使用属性导出

public class ProducerExporter
{
   [Export]
   public IProducer MyProducer
   {
       get
       {
           var producer = new Producer();
           // complex initialization here
           return producer;
       }
   }
}

请注意,术语 factory 并不适合您的示例,我会为导入器想要随意创建实例的情况保留该术语,可能是通过提供一个或多个参数。这可以通过方法导出

来完成
public class ProducerFactory
{
   [Export(typeof(Func<Type1,Type2,IProducer>)]
   public IProducer CreateProducer(Type1 arg1, Type2 arg2)
   {
       return new Producer(arg1, arg2);
   }
}

在导入方面,您将导入一个可以随意调用的Func<Type1,Type2,IProducer>来创建新实例。