3

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;
    }
}

「新しい」コードを自分で書かなければならない場合、次のようになります。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 を実装する方法については、次のような記事が多数あります。

  1. エクスポート プロバイダーを使用した MEF + オブジェクト ファクトリ
  2. 動的インスタンス化

ただし、例は理想的ではありません。

  1. アプリケーションには、依存関係や知識はなくProducer、 のみIProducerです。の作成時にファクトリを登録することはできませんCompositionContainer
  2. Producerは複数のアプリケーションで再利用され、開発者は の作成時に誤ってファクトリを登録するのを忘れる可能性がありCompositionContainerます。
  3. カスタム ファクトリを必要とするタイプは多数あり、 の作成時にファクトリを登録することを忘れないでCompositionContainerください。

ExportProvider の作成を開始しました (これにより、ファクトリを使用して構築を実装する手段が提供されると仮定します)。

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

ただし、FactoryAttribute で定義されたファクトリ オブジェクトを使用し、そのような属性が存在しない場合は既定の作成メカニズムを使用するように MEF に指示する方法がわかりません。

これを実装する正しい方法は何ですか? MEF 2 Preview 5と .NET 4を使用しています。

4

1 に答える 1

3

プロパティのエクスポートを利用できます:

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

ファクトリという用語は、あなたの例には実際には適切ではないことに注意してください.1つ以上のパラメーターを提供することにより、インポーターが自由にインスタンスを作成したい場合のために、その用語を予約します. これはメソッド exportで行うことができます:

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>インポート側では、新しいインスタンスを作成するために自由に呼び出すことができる をインポートします。

于 2012-05-06T10:22:13.313 に答える