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

发布于 2024-09-18 16:12:26 字数 1285 浏览 3 评论 0 原文

我的应用程序使用 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 模块中,而不是它们所在的程序集中)

My application is using MEF to export some classes from an external assembly. These classes are setup for constructor injection. The issue I am facing is that
MEF is attempting to instantiate the classes when I try to access them. Is there a way to have Ninject take care of the instantiation of the class?

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;

Update:

There are multiple classes that implement IMyInterface and I would like to select the one that has a specific name and then have Ninject create an instance of it. I'm not really sure if I want laziness.

[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;
     }


}

Using MEF, I would like to get either MyClassOne or MyClassTwo and then have Ninject provide an instance of MyRepository and YourRepository (Note, these two are bound in a Ninject module in the main assembly and not the assembly they are in)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最舍不得你 2024-09-25 16:12:26

您可以使用 Ninject Load 机制 将导出的类混合在一起,并且您可以:

kernel.GetAll<IMyInterface>()

创建是惰性的(即 IMyInterface 的每个 impl是在迭代上面的 IIRC 时动态创建的,但请查看 源代码 (这是非常干净和可读的,你没有借口:P)可以肯定。

如果您不需要懒惰,请使用 LINQ 的 ToArrayToList 来获取 IMyInterface[]List >

或者您可以使用低级 Resolve() 系列方法(再次查看示例测试)来获取符合条件的服务 [如果您想做一些过滤或其他操作不仅仅是使用实例 - 尽管绑定元数据可能是那里的解决方案]

最后,如果您可以编辑您是否需要懒惰本身或正在这样做来说明一点的解释。 (并在这里搜索 Lazy ,一般来说,Ninject 和 autofac 都适用于某些示例 - 不记得源代码中是否有任何示例 - 不要想,因为它仍在 3.5 上)

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

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

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

然后,当您在父程序集中进行解析时,您可以使用 Kernel.Get<> 重载,该重载采用 name 参数来指示您想要的参数(无需惰性、数组或 IEnumerable)。 Named 机制是 Ninject 中绑定元数据概念的特定应用(仅一两个辅助扩展根据广义概念实现它) - 如果超出简单名称的某些内容,则有足够的空间来自定义它是不够的。

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

我还不清楚为什么你觉得你需要混合并破坏两者 - 最终在构造和构造函数注入期间共享职责不是这两个库的核心用例,即使它们都是非常可组合的库。你是否有限制,或者双方都有关键的利益?

You could use the Ninject Load mechanism to get the exported classes into the mix, and the you either:

kernel.GetAll<IMyInterface>()

The creation is lazy (i.e., each impl of IMyInterface is created on the fly as you iterate over the above) IIRC, but have a look at the tests in the source (which is very clean and readable, you have no excuse :P) to be sure.

If you dont need the laziness, use LINQ's ToArray or ToList to get a IMyInterface[] or List<IMyInterface>

or you can use the low-level Resolve() family of methods (again, have a look in the tests for samples) to get the eligible services [if you wanted to do some filtering or something other than just using an instance - though binding metadata is probably the solution there]

Finally, if you can edit in an explanation of whether you need laziness per se or are doing it to illustrate a point. (and have a search for Lazy<T> here and in general wrt both Ninject and autofac for some samples - cant recall if there are any examples in the source - think not as it's still on 3.5)

EDIT: In that case, you want a bind that has:

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

in the registrations in your modules in the child assembly.

Then when you're resolving in the parent assembly, you use the Kernel.Get<> overload that takes a name parameter to indicate the one you want (no need for laziness, arrays or IEnumerable). The Named mechanism is a specific (just one or two helper extensions implement it in terms of the generalised concept) application of the binding metadata concept in Ninject - there's plenty room to customise it if somethng beyond a simple name is insufficient.

If you're using MEF to construct the objects, you could use the Kernel.Inject() mechanism to inject properties. The problem is that either MEF or Ninject
- has to find the types (Ninject: generally via Bind() in Modules or via scanning extensions, after which one can do a Resolve to subset the bindings before instantiation - though this isnt something you normally do)
- has to instantiate the types (Ninject: typically via a Kernel.Get(), but if you discovered the types via e.g. MEF, you might use the Kernel.Get(Type) overloads )
- has to inject the types (Ninject: typically via a Kernel.Inject(), or implicit in the `Kernel.Get())

What's not clear to me yet is why you feel you need to mix and mangle the two - ultimately sharing duties during construction and constructor injection is not a core use case for either lib, even if they're both quite composable libraries. Do you have a constraint, or do you have critical benefits on both sides?

横笛休吹塞上声 2024-09-25 16:12:26

您可以使用 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
希望这有帮助

You can use ExportFactory to create Instances
see docs here:

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

Your case would be slitly different
I would use Metadata and a custom attribute also

[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; 
}

or use return Controllers.First() without the Metadata

Then you can code the ninject parts around that or even stick with MEF
Hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文