2011-01-06 2 views
6

私はDIコンテナとしてMEFを使用していますが、問題は複数の部分から特定の部分をインポートしたいということです。MEFの複数の部品から特定の部品をインポートするにはどうすればよいですか?

例えば、私は次のようしているコード:

public interface IService 
{ 
    void Send(); 
} 

[Export(typeof(IService))] 
public class Service : IService 
{ 
    public void Send() 
    { 
     Console.WriteLine("Service.Send"); 
    } 
} 

[Export(typeof(IService))] 
public class FakeService : IService 
{ 
    public void Send() 
    { 
     Console.WriteLine("FakeService.Send"); 
    } 
} 

[Import] 
public IService Service { get; set; } // ---> let's say I want to use FakeService 

は、任意の解決策はありますか?

ありがとうございます

答えて

13

、ここでの例です:私たちは、メタデータの契約を定義することができる

public interface ILogger 
{ 
    void Log(string message); 
} 

[Export(typeof(ILogger)), ExportMetadata("Name", "Console")] 
public class ConsoleLogger : ILogger 
{ 
    public void Log(string message) 
    { 
    Console.WriteLine(message); 
    } 
} 

[Export(typeof(ILogger)), ExportMetadata("Name", "Debug")] 
public class DebugLogger : ILogger 
{ 
    public void Log(string message) 
    { 
    Debug.Print(message); 
    } 
} 

はその契約およびそれらの実装例を考えると、我々はLazy<T, TMetadata>ようなタイプをインポートすることができます。

public interface INamedMetadata 
{ 
    string Name { get; } 
} 

MEFはExportMetadata属性値を具体的な実装としてTMetadata(この例では01)として投影するため、メタデータの実装の作成について心配する必要はありません。上記で、私は次の例を作成することができます。そのサンプルクラスで

public class Logger 
{ 
    [ImportMany] 
    public IEnumerable<Lazy<ILogger, INamedMetadata>> Loggers { get; set; } 

    public void Log(string name, string message) 
    { 
    var logger = GetLogger(name); 
    if (logger == null) 
     throw new ArgumentException("No logger exists with name = " + name); 

    logger.Log(message); 
    } 

    private ILogger GetLogger(string name) 
    { 
    return Loggers 
     .Where(l => l.Metadata.Name.Equals(name)) 
     .Select(l => l.Value) 
     .FirstOrDefault(); 
    } 
} 

が、私は Lazy<ILogger, INamedMetadata>インスタンスとして、多くのインスタンスをインポートしています。 Lazy<T,TMetadata>を使用すると、値にアクセスする前にメタデータにアクセスできます。上記の例では、私は name引数を使用して、使用する適切なロガーを選択しています。

インポート時にクラスをインスタンス化するのが適切でない場合は、ExportFactory<T,TMetadata>を使用すると、必要に応じて型のインスタンスをスピンアップできます。 (ExportFactoryは、.NET 4.0のSilverlightのバージョンに含まれていますが、グレン・ブロックは、デスクトップ/ウェブ用にソースコードon codeplexを投げました。

を、私はそれが役に立てば幸い。

3

また、契約の名前を取るエクスポートのオーバーロードを使用することもできます。次に、契約名でインポートします。

[Export("Service", typeof(IService))] 
public class Service : IService { 
} 

[Export("FakeService", typeof(IService))] 
public class FakeService : IService { 
} 

[Import("FakeService")] 
public IService Service { get; set; } 
+0

おかげでジョシュが、私は契約名を使用しようとしていました私の問題を解決しましたが、輸出部品で契約名を使用すると、ImportManyを使用できません。輸入部品を一緒にインポートするImportManyを使用する方法はありますか? – Ray

+0

一般的に、ImportManyとImportManyを簡単に組み合わせることはできませんあなたがインポートを持っていて、複数のエクスポートがある場合、同じ例外が発生します。ただし、コンストラクタでImportManyを実行して、別のロジックに基づいてインポートされたものを選択できます。 – Josh

0

エクスポートのメタデータを追加して、それぞれのエクスポートを区別することができます。インポート側では、ImportManyを使用してメタデータに基づいてフィルターをかけ、必要なものを見つける必要があります。あなたのクラスにメタデータをエクスポートすることができます

関連する問題