Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 4.0 如何扩展MEF以基于作为属性提供的工厂类型创建对象?_C# 4.0_Mef - Fatal编程技术网

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
    ),所有权的工作方式相同(容器拥有对象,并在必要时对其进行处理)。