3

MEFを使用してプラグインベースのアプリケーションを構築し始めており、ゆっくりとMEFをミックスに追加しています。MEF DNAをまだ持っていない既存のコードはたくさんありますが、それでも、合成によって自動的に作成される新しいオブジェクトにそのコードを取り込みたいと思います。

これを具体的にしましょう。

IFooインターフェイスを実装し、特定の便利な方法でアプリケーションモデルを操作するオブジェクトのリストがあります。

interface IFooCool : IFoo {}

class FooCool : IFooCool {...}

interface IFooAwesome : IFoo {}

class FooAwesome : IFooAwesome {}

IEnumerable<IFoo> fooCollection = ProvidedTheOldFashionWay(not, yet, MEF);

IFooXここで、インターフェイスをメニューコマンドやボタンクリックなどのさまざまなユーザーアクションに マップする便利なツールをいくつか作成したいと思います。

[Export(ITool)]
class CoolTool : ITool
{
    IFooCool _fooCool;
    [ImportingConstructor]
    CoolTool(IFooCool fooCool) 
    {
        _fooCool = fooCool;
    }

    [Export(MenuAction)]
    void DoSomething() { _fooCool.SomeWork(...); }
}

これが私がやりたいことです:

var batch = new CompositionBatch();
foreach(var foo in fooCollection)
{
    batch.AddPart(foo);  //add those legacy objects to the batch
}

var catalog = new TypeCatalog(typeof(CoolTool));  //or assembly or directory, ...
var container = new CompositionContainer(catalog);

container.Compose(batch);

CoolToolがインスタンス化され、レガシーFooCoolオブジェクトが渡されます。次に、エクスポートされた関数を取得して、メニューに適切に表示します。ユーザーがメニュー項目をクリックすると、新しいものCoolToolはインターフェースの既存の機能を使用してIFooCool、何か、まあ、クールなことをします。

もちろん、それは機能しません。レガシーオブジェクトはエクスポートとして関連付けられていないため、コンポジションバッチに追加しても効果はありません。batch.AddPart(object)上記のコードでは、.の代わりにfooインスタンスをバッチに追加していますbatch.AddPart(ComposablePart)。最初のメソッドは、属性付きモデルを使用して、オブジェクトから構成可能な情報を検出します。

2番目のオーバーロードをどのように使用できますか?既存の非MEFオブジェクトをその場でComposablePartにラップできますか?何かのようなもの:

batch.AddPart(CreateComposablePart(typeof(IFooCool), foo));

ところで、私は非Silverlightアプリでプレビュー8を使用しています。

4

3 に答える 3

1

そして、方法があります-ある種。

batch.AddExportedValue(typeof(IFooCool).Fullname, (IFooCool)foo);

残念ながら、問題はそれよりも少し複雑です。エクスポートとしてマークする必要があるfooは、実際には次のとおりです。

Dictionary<Type, IFoo> _registeredFoos;

IFooCool      => FooCool
IFooAwesome   => FooAwesome

そして、以下(IFooCoolキャストなし)は機能しません:

batch.AddExportedValue(typeof(IFooCool).Fullname, foo);

だから私は本当にこのようにfoosをループする必要があります:

foreach(var entry in _registeredFoos)
{
    batch.AddExportedValue(entry.Key.Fullname, // that was easy...
                          (?)entry.Value);     // what?  This is a generic method...
}

さて、私はソースをクラックして開いて、何が起こっているのかを見ていきます。素晴らしい解決策でしょ?フレームワーク関数の内部の詳細を知り、活用することは、アプリを開発するための健全な方法です。私はこれを行います:

foreach(var entry in _registeredFoos)
{
    string typeIdentity = AttributedModelServices.GetTypeIdentity(entry.Key);
    IDictionary<string, object> metadata = new Dictionary<string, object>();
    metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity);

    Export export = new Export(entry.Key, metadata, () => entry.Value);
    batch.AddExport(export);
}

もちろん。今、私はシャワーを浴びに行く必要があります。

于 2010-01-08T23:01:23.350 に答える
1

この拡張メソッドを呼び出そうとしているようです。

AttributedModelServices.AddExportedValue<T>(
   this CompositionBatch batch,
   string contractName,
   T exportedValue);

問題は、T実行時に型パラメーターしかわからないことです。それはあなたの辞書の鍵です。1つの解決策は、リフレクションを使用してメソッドを呼び出すことです。これにより、実行時に型パラメーターを入力できます。まず、次のMethodInfoようなジェネリックメソッドを取得します。

MethodInfo genericAddExportedValue = 
   typeof(AttributedModelServices).GetMethods()
   .Where(x=>x.Name == "AddExportedValue")
   .First(x=>x.GetParameters().Count() == 3);

これで、ループ内のtypeパラメーターを閉じて、メソッドを呼び出すことができます。

foreach(var entry in _registeredFoos)       
{       
    MethodInfo addExportedValue = 
       genericAddExportedValue.MakeGenericMethod(entry.Key);
    addExportedValue.Invoke(
       null,
       new object[] {batch, entry.Key.FullName, entry.Value});
}

または、ディクショナリをExportProvider使用してエクスポートを提供する方法を知っている抽象クラスの実装を作成することもできます。_registeredFoosしかし、それはおそらくもっと多くの作業です。

于 2010-01-09T03:08:15.373 に答える
0

MEFパーツとして属性のないレガシークラスを使用するには、MEFContribの一部であるConfigurableDefinitionProviderを使用できます。これにより、属性の代わりに構成ファイルを使用してインポートとインポートを定義できます。

(あなた自身の答えによって明らかにされたあなたの質問は、実際にはあなたがすでに利用できるパーツを追加する方法ですがDictionary<Type,object>、質問のタイトルによって提案されたより簡単な質問に答えることも面白いかもしれないと思いました。)

于 2010-01-11T14:26:27.630 に答える