Ninject:注入两个相同类型的不同对象 [英] Ninject: Injecting two different objects of same type

查看:128
本文介绍了Ninject:注入两个相同类型的不同对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个类,它对同一个类型具有双重依赖关系(需要两个不同的实例),如果实例之间的唯一区别是更深的依赖关系,那么让Ninject执行DI并保留两个图的最佳方法是什么分开吗?

If I have a class, which has dual dependencies on the same type (needs two different instances), if the only difference between the instances is a deeper dependency, what's the best way to have Ninject perform DI and keep the two graphs separate?

示例对象图:

foo → ClassA → ClassB
bar → ClassA → ClassB

C的构造函数:

Class C's constructor:

public class C
{
    public C(ClassB foo, ClassB bar) { … }
}

所以我如何确保用foo实例化的ClassB作为ClassB依赖项foobar…提供. bar?

So how do I make sure that the ClassB instantiated with foo gets supplied as the ClassB dependancy foo, and barbar?

仅出于某些背景,我对需求进行了一些更改,因此我需要用复合的只写存储库替换只写存储库(IAdd)

Just for some background, I had some requirements change, so I need to replace a write-only repository (IAdd) with a composite write-only repository

public class CompositeWriteRepository<T> : IAdd<T>
{
    public CompositeWriteRepository(IAdd<T> foo, IAdd<T> bar, Func<T, bool> descriminator) { ... }
    public Add(T entity)
    {
        if (descriminator(entity)) {
            foo.Add(entity);
        } else {
            bar.Add(entity);
        }
    }        
}

通过模拟,这很容易,我可以使用名称进行注入:

With mocking, that was easy enough, I could just inject using names:

 kernel.Bind<IAdd<EntityType>>().To<fooRepository>().Named("foo");
 kernel.Bind<IAdd<EntityType>>().To<barRepository>().Named("bar");

 kernel.Bind<IAdd<EntityType>>().To<CompositeWriterRepository<EntityType>>()
    .WithConstructorArgument("foo", x => x.Kernel.Get<IAdd<EntityType>>("foo")
    .WithConstructorArgument("bar", x => x.Kernel.Get<IAdd<EntityType>>("bar");

问题出在我使用真实存储库时; foobar最终会写入文件,因此它们需要不同的文件名.由于它们是StreamWriter存储库,因此它们的依赖项之一实际上获得了两个不同的文件名.

The problem comes when I use the real repositories; foo and bar ultimately write to files so they need different file names. Since they're StreamWriter repositories, one of their dependencies actually gets the two different file names.

string FileName → FileStreamWriterFactory → StreamRepository → CompositeRepository

到目前为止,我发现构造事物的唯一方法是制作一个名为FileName,名为FileStreamWriterFactory,名为StreamRepository×的文件. 2(对于foo一次,对于bar一次).这似乎是很多工作,所以我希望有更好的解决方案.

The only way I've found thus far to construct things is to make a named FileName, named FileStreamWriterFactory, named StreamRepository × 2 (once for foo and once for bar). This seems like a lot of work, so I hope there's a better solution.

我可以根据需要重新进行架构设计,这感觉就像是一种优雅的方法,可以在需求发生变化时快速添加分隔条目.我意识到我的课程都是非常具体的,但是我认为单一职责通常可以支持这一点,在我的情况下,我们编写了许多小型应用程序,并且有更多可以满足的请求,因此这是拥有大量可重用代码的好方法我基本上只需要针对不同的任务进行重新配置.

I can re-architect if needed, it felt like an elegant way to quickly add in seperating the entries when the requirements changed. I realize my classes all are quite specific, but I think single responsibility would support this generally and in my case we write a bunch of small applications and have more requests the we can fulfill so its a good way to have lot's of re-usable code laying around that I basically just need to re-configure for different tasks.

解决方案
雷莫·格洛(Remo Gloor)应该获得信誉;他可能是最佳做法.

Solution
Remo Gloor should get credit; his is probably the best practice.

我实际上所做的是创建一个新的扩展名

What I actually did was create a new extension

public static bool WhenAnchester(this IRequest request, Func<IRequest, bool> conditions)
{
    var parentContext = request.ParentContext;
    if (parentContext == null) {
            return false;
    }

    return conditions(parentContext.Request) || 
        parentContext.Request.WhenAnchester(conditions);
} 

然后,我可以轻松地控制将哪个文件注入到哪个存储库中.

This then let me easily control which file get injected into which repository.

kernel.Bind<string>().ToConstant("Foo.txt")
    .When(x => x.Target.Name == "filepath" && 
              x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest1"));

kernel.Bind<string>().ToConstant("Bar.txt")
    .When(x => x.Target.Name == "filepath" &&
               x.WhenAnchester(t => t.Target != null && t.Target.Name == "Dest2"));

可能有更好的解决方案,因此我没有必要向其他人推荐此方法,但是它对我来说效果很好.

There's probably a better solution, so I wouldn't necessary recommend this for others, but its working well for me.

推荐答案

是的,还有更好的方法

请参见 https://github.com/ninject/ninject/commit/60443badf4ef840531c93e9287b154a9bba337c2

See https://github.com/ninject/ninject/commit/60443badf4ef840531c93e9287b154a9bba337c2

它是3.0,但是IsAnyAnchestorNamed也可以与When条件中的2.2一起使用.

It's 3.0 but IsAnyAnchestorNamed can also be used with 2.2 from a When condition.

这篇关于Ninject:注入两个相同类型的不同对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆