2

Codeplexホームページから最新のMEF2プレビューを使用していますが、オープンジェネリックサポートが追加されることになっています。そうですが、この特定のケースでは、MEFはジェネリックインターフェイスのジェネリック実装を構成できません。

public interface IOuter
{
    IInner Value { get; }
}

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [ImportingConstructor]
    public MyOuter(InnerGenericClass<string, int> value)
    {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}

public interface IInner
{
    void Say();
}
public interface IGenericInner<T, K> : IInner
{
    // something else here
}

[Export(typeof(IGenericInner<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K>
{
    public void Say()
    {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
}

class Startup
{
    public void CatalogSetup()
    {
        var catalog = new AggregateCatalog(
            new AssemblyCatalog(Assembly.GetExecutingAssembly())
            );
        var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);

        var batch = new CompositionBatch();

        container.Compose(batch);

        var outer = container.GetExportedValue<IOuter>();
        outer.Value.Say();
    }
}

これがCompositionExpectionです:

The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) No exports were found that match the constraint: 
    ContractName    ConsoleApplication1.InnerGenericClass(System.String,System.Int32)
    RequiredTypeIdentity    ConsoleApplication1.InnerGenericClass(System.String,System.Int32)

Resulting in: Cannot set import 'ConsoleApplication1.MyOuter.Value (ContractName="ConsoleApplication1.InnerGenericClass(System.String,System.Int32)")' on part 'ConsoleApplication1.MyOuter'.
Element: ConsoleApplication1.MyOuter.Value (ContractName="ConsoleApplication1.InnerGenericClass(System.String,System.Int32)") -->  ConsoleApplication1.MyOuter -->  AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Resulting in: Cannot get export 'ConsoleApplication1.MyOuter (ContractName="ConsoleApplication1.IOuter")' from part 'ConsoleApplication1.MyOuter'.
Element: ConsoleApplication1.MyOuter (ContractName="ConsoleApplication1.IOuter") -->  ConsoleApplication1.MyOuter -->  AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

InnerGenericClassのインポートをMyOuter.Valueの属性に移動しても、同じ例外がスローされます。

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [Import(typeof(InnerGenericClass<string, int>))]
    public IInner Value { get; private set; }
}

奇妙なことに、インポートタイプをIGenericInnerに変更すると、機能します

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [ImportingConstructor]
    public MyOuter(IGenericInner<string, int> value)
    {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}

さらに奇妙なのは、属性を介してインポートすると機能しないことです。

概要:ジェネリックインターフェイスを使用してオブジェクトをValueプロパティにインポートすることはできません。これは、 IGenericInnerインターフェイスの実装がさらに存在する可能性があるためです(特定の実装をインポートしたいのですが、それは重要ではありません)。

この場合、MEFを完全にバイパスする必要がないことを願っています。

4

1 に答える 1

5

インターフェイスIGenericInner<>をエクスポートしましたが、特定のクラスをインポートしたい場合InnerGenericClassMEFは正しい部分を見つけられません。次の方法で、特定のクラスをエクスポートしてインポートするか、InnerGenericClass<>の2つのエクスポートを作成できます。

[Export(typeof(IGenericInner<,>))]
[Export(typeof(InnerGenericClass<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K> {
    public void Say() {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
}

これをVS.NET4.5プロジェクトでテストしたところ、機能します。ところで。MEF2はすでに.NET4.5でリリースされています-可能であれば、プレビューバージョンではなくフレームワークのSystem.ComponentModel.Composition.dll部分を使用することをお勧めします。

更新:3番目の解決策(プレビューバージョン5で機能します)は、文字列コントラクト名を追加で使用することです。私は個人的にこの醜い構文の原因を避けようとしますが、大丈夫です。コードは次のようになります。

[Export(typeof(IOuter))]
public class MyOuter : IOuter {
    [ImportingConstructor]
    public MyOuter([Import("MySpecialInnerGenericClass", typeof(IGenericInner<,>))]InnerGenericClass<string, int> value) {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}
[Export("MySpecialInnerGenericClass", typeof(IGenericInner<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K> {
    public void Say() {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
} 
于 2013-02-20T08:54:22.763 に答える