Ninject:注入两个相同类型的不同对象

W3t*_*r3y 8 c# ninject

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

示例对象图:

foo ? ClassA ? ClassB
bar ? ClassA ? ClassB
Run Code Online (Sandbox Code Playgroud)

C的构造函数:

public class C
{
    public C(ClassB foo, ClassB bar) { … }
}
Run Code Online (Sandbox Code Playgroud)

那么我如何确保ClassB实例化的是foo作为ClassB依赖性提供的foo,并且bar...... bar

仅仅为了某些背景,我有一些需求更改,所以我需要用只读的只写存储库替换只写存储库(IAdd)

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);
        }
    }        
}
Run Code Online (Sandbox Code Playgroud)

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

 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");
Run Code Online (Sandbox Code Playgroud)

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

string FileName ? FileStreamWriterFactory ? StreamRepository ? CompositeRepository
Run Code Online (Sandbox Code Playgroud)

我发现迄今建造的东西,唯一的办法就是让一个叫FileName,叫FileStreamWriterFactory,叫StreamRepository(一次×2 foo的一次bar).这似乎很多工作,所以我希望有一个更好的解决方案.

如果需要,我可以重新设计,感觉就像是一种优雅的方式,可以在需求变化时快速添加分隔条目.我意识到我的课程都非常具体,但我认为单一的责任通常会支持这一点,在我的情况下,我们编写了一堆小应用程序并且有更多的请求我们可以实现,因此它是一个很好的方法来获得大量的可重用代码我基本上只需要重新配置不同的任务.

解决方案
雷莫格洛尔应该获得信誉; 他可能是最好的做法.

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

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);
} 
Run Code Online (Sandbox Code Playgroud)

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

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"));
Run Code Online (Sandbox Code Playgroud)

可能有一个更好的解决方案,所以我不需要为其他人推荐这个,但它对我来说效果很好.

Rem*_*oor 4

是的,有更好的方法

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

它是 3.0,但 IsAnyAnchestorNamed 也可以在 When 条件下与 2.2 一起使用。