web-dev-qa-db-ja.com

MEFコンストラクターインジェクション

MEFのコンストラクターインジェクション属性を理解しようとしています。コンストラクターのパラメーターをロードするように指示する方法がわかりません。

これは私がロードしようとしているプロパティです

[ImportMany(typeof(BUsers))]
public IEnumerable<BUsers> LoadBUsers { get; set; }

アセンブリのインポートに使用するコードは次のとおりです。

try
{
    var catalog = new AggregateCatalog();
    catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
    catalog.Catalogs.Add(new DirectoryCatalog("DI")); 
    var container = new CompositionContainer(catalog);
    container.ComposeParts(this);
}

これが私がロードしようとしているクラスです

[Serializable]
[Export(typeof(BUsers))]
public class EditProfile : BUsers
{
    [ImportingConstructor]
    public EditProfile(string Method, string Version)
    {            
        Version = "2";
        Action = "Edit";
        TypeName = "EditProfile";
    }
39
alpha

ImportingConstructor属性を使用すると、コンストラクターのパラメーターがインポートになります。デフォルトでは、インポートするもの(契約名)は、インポート先のパラメーターまたはプロパティのタイプに基づいています。したがって、この場合、両方のインポートのコントラクトタイプは文字列であり、最初のパラメーターと2番目のパラメーターの間に実際の違いはありません。

インポートを使用して構成値を提供しようとしているようですが、これは必ずしも設計されたものではありません。これを希望どおりに実行するには、次のように、各パラメーターのコントラクト名をオーバーライドする必要があります。

[ImportingConstructor]
public EditProfile([Import("Method")] string Method, [Import("Version")] string Version)
{ }

次に、メソッドとバージョンをコンテナにエクスポートする必要があります。これを行う1つの方法は、それらを直接追加することです。

var container = new CompositionContainer(catalog);
container.ComposeExportedValue("Method", "MethodValue");
container.ComposeExportedValue("Version", "2.0");
container.ComposeParts(this);

(ComposeExportedValueは、実際には静的なAttributedModelServicesクラスで定義された拡張メソッドであることに注意してください。)

ある種の構成ファイルからこれらの値を読み取る場合は、構成を読み取り、その値をコンテナーへのエクスポートとして提供する独自のエクスポートプロバイダーを作成できます。

これを処理する別の方法は、構成値に名前でアクセスできるインターフェースをインポートし、コンストラクターの本体から必要な値を取得することです。

56
Daniel Plaisted

私はダニエルの解決策が好きです。ただし、私が目にする唯一のことは、カスタマイズされたCTORの[ImportingConstructor]を使用して、アクター(CompopositionContrainer()を作成する)とエクスポートパーツの間のパラメーター名の密結合です。たとえば、「メソッド」は両方で一致します。アクターとエクスポートパーツが異なるプロジェクトにある場合、エクスポートパーツのメンテナンスが難しくなります。

可能であれば、2番目のCTORをエクスポートパーツクラスに追加します。例えば:

[Export(typeof(BUsers))] 
public class EditProfile : BUsers
{
    [ImportingConstructor]
    public EditProfile(EditProfileParameters ctorPars)
    : this(ctorPars.Method, ctorPars.Version) {}

    public EditProfile(string Method, string Version)
    {
        Version = "2";
        Action = "Edit";
        TypeName = "EditProfile";
    }

EditProfileParametersのクラスは単純である必要があります:メソッドとバージョンの2つのプロパティ:

[Export]
public class EditProfileParameters{
   public string Method { get; set; }
   public string Version { get; set; }
}

重要な点は、Export属性をクラスに追加することです。次に、MEFはこのクラスをEditProfileのCTORのパラメーターにマップできるはずです。

次に、エクスポートパーツをコンテナに追加する例を示します。

var container = new CompositionContainer(catalog);
var instance1 = new EditProfileParameters();
// set property values from config or other resources
container.ComposeExportedValue(instance1);
container.ComposeParts(this);
24
David.Chu.ca

ゲームに遅れましたが、MEFのあまり知られていない機能を活用する別のアプローチがあります。プロパティのエクスポート

public class ObjectMother
{
    [Export]
    public static EditProfile DefaultEditProfile
    {
        get
        {
            var method = ConfigurationManager.AppSettings["method"];
            var version = ConfigurationManager.AppSettings["version"];

            return new EditProfile(method,version);
        }
    }
}

これが機能するためにObjectMotherを使用する必要はなく、EditProfileに属性は必要ありません。

1
bryanbcook