【问题标题】:How to instantiate a MEF exported object using Ninject?如何使用 Ninject 实例化 MEF 导出的对象?
【发布时间】:2010-09-06 22:53:29
【问题描述】:

我的应用程序正在使用 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 模块中,并且不是他们所在的大会)

【问题讨论】:

  • 我的回答有用吗?如果没有,我想让它变得更好。即使我的答案离题而且我不能给你一个满意的答案,你应该跟进以最大化你的赏金价值,因为其他人也会猜测缺少什么......?

标签: dependency-injection mef ninject


【解决方案1】:

您可以使用Ninject Load mechanism 将导出的类加入其中,您可以:

kernel.GetAll<IMyInterface>()

创建是惰性的(即,IMyInterface 的每个 impl 都是在您迭代上述内容时动态创建的)IIRC,但请查看source 中的测试(非常干净易读,你没有任何借口 :P) 可以肯定。

如果您不需要懒惰,请使用 LINQ 的 ToArrayToList 获取 IMyInterface[]List&lt;IMyInterface&gt;

或者您可以使用低级别的Resolve() 系列方法(再次查看样本测试)来获得符合条件的服务[如果您想做一些过滤或其他事情,而不仅仅是使用实例- 虽然绑定元数据可能是那里的解决方案]

最后,如果您可以编辑说明您是否需要懒惰本身或这样做是为了说明一点。 (并在此处搜索Lazy&lt;T&gt; 并且通常在 Ninject 和 autofac 中搜索一些示例 - 不记得源中是否有任何示例 - 不要认为它仍在 3.5 上)

编辑:在这种情况下,您需要一个具有:

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

在子程序集中的模块注册中。

然后,当您在父程序集中解析时,您使用 Kernel.Get&lt;&gt; 重载,该重载采用 name 参数来指示您想要的那个(不需要惰性、数组或 IEnumerable)。 Named 机制是 Ninject 中绑定元数据概念的一种特定应用(仅一个或两个辅助扩展就通用概念实现了它)——如果除了简单的名称之外还有足够的空间来定制它。

如果您使用 MEF 来构造对象,则可以使用 Kernel.Inject() mechanism 来注入属性。问题是 MEF 或 Ninject - 必须找到类型(Ninject:通常通过Modules 中的Bind() 或通过扫描扩展,之后可以在实例化之前执行Resolve 来对绑定进行子集化 - 虽然这不是你通常做的事情) - 必须实例化类型(Ninject:通常通过 Kernel.Get(),但如果您通过例如 MEF 发现类型,则可以使用 Kernel.Get(Type) overloads) - 必须注入类型(Ninject:通常通过Kernel.Inject(),或隐含在`Kernel.Get())

我还不清楚为什么你觉得你需要混合和破坏这两者 - 最终在构造和构造函数注入期间共享职责不是任何一个库的核心用例,即使它们都是相当可组合的库。您是否有限制,或者您对双方都有重要的好处?

【讨论】:

  • 更新了答案,提供了更多信息。另外,您能否提供指向您所指测试的链接。我似乎找不到它们。
  • @Baddie:我认为你更新了“答案”:D 我更新了我的(有更多问题!)我指的是测试,我会做一个“完整的” '' 主干,然后在文件中查找 IEnumerable 和/或单词lazy(认为某些[Fact]s 有类似解决方案的标题应该是惰性的)注意,根据您的说明,这不再是您想要的.
  • 虽然使用 Named 方法对我来说很好,但我不会使用 MEF 来发现这些类。
  • @Baddie:那你排好了吗?您需要图片中的 MEF 还是只使用 Ninject 很开心?您还在寻找纯 MEF 解决方案吗?还有什么不清楚的吗?
【解决方案2】:

您可以使用 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。
猜你喜欢
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多