如何使用Ninject实例化一个MEF导出的对象?

10

我的应用程序正在使用MEF从外部程序集导出一些类。这些类已设置为构造函数注入。我遇到的问题是当我尝试访问它们时,MEF会尝试实例化这些类。是否有办法让Ninject处理类的实例化?

IEnumerable<Lazy<IMyInterface>> controllers = 
    mefContainer.GetExports<IMyInterface>();

// The following line throws an error because MEF is 
// trying to instantiate a class that requires 5 parameters
IMyInterface firstClass = controllers.First().Value;

更新:

有多个类实现了IMyInterface,我希望选择一个特定名称的类,然后让Ninject创建它的一个实例。我不确定自己是否需要惰性加载。

[Export(typeof(IMyInterface))]
public class MyClassOne : IMyInterface {

     private MyRepository one;
     private YourRepository two;

     public MyClassTwo(MyRepository repoOne, YourRepository repoTwo) {
            one = repoOne;
            two = repoTwo;
     }         
}

[Export(typeof(IMyInterface))]
public class MyClassTwo : IMyInterface {

     private MyRepository one;
     private YourRepository two;

     public MyClassTwo(MyRepository repoOne, YourRepository repoTwo) {
            one = repoOne;
            two = repoTwo;
     }


}

使用 MEF,我想获取 MyClassOneMyClassTwo 中的一个,然后让 Ninject 提供 MyRepositoryYourRepository 的实例(注意,这两个在主程序集中的 Ninject 模块中绑定,而不是它们所在的程序集中)。


我的回答是否解决了问题?如果没有,我想让它变得更好。即使我的回答完全不正确,我无法给您一个令人满意的答案,您也应该跟进以最大化您的赏金价值,因为其他人也会猜测缺少了哪一部分...? - Ruben Bartelink
2个回答

6
你可以使用Ninject Load机制将导出的类引入,然后你可以选择:
kernel.GetAll<IMyInterface>()

创建是延迟的(即,每个IMyInterface的实现都是在您遍历上述内容时动态创建的),如果我没记错的话,但是请查看source中的测试(非常干净和易读,您没有借口:P)以确保。
如果您不需要惰性,请使用LINQ的ToArray或ToList获取IMyInterface[]或List<IMyInterface>
或者您可以使用低级别的Resolve()方法系列(再次查看样本测试),以获取合适的服务[如果您想要执行一些过滤或其他事情而不仅仅是使用一个实例-尽管绑定元数据可能是解决方案]
最后,如果您可以编辑说明您是否需要懒惰本身还是为了阐明某一点。 (并搜索与Ninject和autofac相关的Lazy<T>以及一般示例-无法回忆是否有源代码中的示例-认为没有,因为它仍然在3.5上)

编辑:在这种情况下,您需要一个具有以下内容的绑定:

Bind<X>().To<>().In...().Named( "x" );

在子程序集中注册模块后,当您在父程序集中解析时,使用带有name参数的Kernel.Get<>重载来指示您想要的模块(不需要懒加载、数组或IEnumerable)。Named机制是Ninject中绑定元数据概念的一个具体应用(只有一两个辅助扩展实现它),如果简单名称不足以满足需求,则可以进行自定义。

如果您正在使用MEF构建对象,您可以使用Kernel.Inject()机制来注入属性。问题在于,无论是MEF还是Ninject - 必须找到类型(Ninject:通常通过Module中的Bind()或通过扫描扩展来查找,之后可以进行Resolve以对绑定进行子集化,但这不是您通常要做的事情) - 必须实例化类型(Ninject:通常通过Kernel.Get(),但如果您通过MEF等方式发现了类型,则可以使用Kernel.Get(Type)重载) - 必须注入类型(Ninject:通常通过Kernel.Inject()或隐含在`Kernel.Get()`中)
我还不清楚的是为什么你觉得需要混合和搭配这两个库——在构建期间共享职责和构造函数注入并不是它们的核心用例,即使它们都是相当可组合的库。你有限制条件吗?或者两边都有重要的好处吗?

更新的答案,附带更多信息。另外,你能提供一下你所指的测试链接吗?我好像找不到。 - Omar
@Baddie:我猜你已经更新了“答案” :D 我也更新了我的(加了更多问题!)关于我指的测试,我会获取''full'' trunk然后在文件中查找IEnumerable和/或lazy这个词(我认为一些[Fact]的标题中应该有像分辨率应该是懒惰的之类的字眼)。注意,根据您的澄清,这不再是您想要的。 - Ruben Bartelink
虽然对我来说使用“Named”方法很好,但我不会使用MEF来发现这些类。 - Omar
@Baddie:你现在解决了吗?你需要MEF参与其中吗,还是只使用Ninject就可以了?你还在寻找纯MEF的解决方案吗?还有其他什么不清楚的地方吗? - Ruben Bartelink

0

您可以使用ExportFactory来创建实例,文档请参见此处:

http://mef.codeplex.com/wikipage?title=PartCreator

你的情况会稍有不同,我会使用元数据和自定义属性。

[ImportMany(AllowRecomposition=true)] 
    IEnumerable<ExportFactory<IMyInterFace, IMyInterfaceMetaData>> Controllers{ get; set; } 

public IMyInterface CreateControllerFor(string parameter)
{
var controller = Controllers.Where(v => v.Metadata.ControllerName == parameter).FirstOrDefault().CreateExport().Value; 
            return controller; 
}

或者使用 return Controllers.First() 而不带元数据

然后你可以编写围绕它的ninject部分或者甚至坚持MEF。 希望这有所帮助。


ExportFactory 类型仅适用于 Silverlight。 - Omar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接