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界面现有的功能做一些事情,嗯,很酷。

当然,这是行不通的。由于遗留对象不属于导出,因此将它们添加到组合批处理中没有帮助。在上面的代码中,我将 foo 实例添加到批处理中,batch.AddPart(object)而不是batch.AddPart(ComposablePart). 第一种方法使用属性模型从对象中发现可组合信息。

如何使用第二个重载?我可以动态地将现有的非 MEF 对象包装在 ComposablePart 中吗?就像是:

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

顺便说一句,我在非 Silverlight 应用程序中使用预览 8。

4

3 回答 3

1

看起来您正在尝试调用此扩展方法:

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

你的问题是你只知道T运行时的类型参数;它是你字典的键。一种解决方案是使用反射来调用该方法,这使您能够在运行时填写类型参数。首先,得到这样MethodInfo的泛型方法:

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

现在您可以关闭循环内的类型参数并调用该方法:

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 回答
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 回答
0

要将没有属性的遗留类用作 MEF 部件,您可以使用ConfigurableDefinitionProvider,它是 MEFContrib 的一部分。这允许您使用配置文件而不是属性来定义导入和导入。

(您自己的回答澄清了您的问题实际上是如何添加您已经作为 a 可用的部分Dictionary<Type,object>,但我认为回答问题标题建议的更简单的问题也可能很有趣。)

于 2010-01-11T14:26:27.630 回答