Ninject多个绑定取决于ctor参数名称

时间:2015-12-10 09:25:49

标签: c# dependency-injection ninject

假设我有以下接口:

public interface ISomething { };

public interface IResolver
{
    string ResolveBy(ISomething something);
}

现在我有两种解析器类型;一个提供最佳解决方案,但有机会失败的解决方案,一个解决方案,总能返回一个解决方案,这应该作为后备策略:

public class UnsafeResolver : IResolver
{
    Random random = new Random();

    public string ResolveBy(ISomething something)
    {
        if (random.NextDouble() > 0.5)
        {
            return "best solution ever!";
        }
        else
        {
            throw new InvalidOperationException("something went wrong...");
        }
    }
}

public class SafeResolver : IResolver
{
    public string ResolveBy(ISomething something)
    {
        return "fallback solution";
    }
}

现在我想在受保护的合成装饰器中合并两个解析器:

public class SafeguardedResolver : IResolver
{
    private readonly IResolver unsafeResolver;
    private readonly IResolver safeResolver;

    // This is the problem with Ninject: Two parameters with same interface...
    public SafeguardedResolver(IResolver unsafeResolver, IResolver safeResolver)
    {
        // guards omitted!
        this.unsafeResolver = unsafeResolver;
        this.safeResolver = safeResolver;
    }

    public string ResolveBy(ISomething something)
    {
        try
        {
            return unsafeResolver.ResolveBy(something);
        }
        catch (InvalidOperationException)
        {
            return safeResolver.ResolveBy(something);
        }
    }
}

所以我的问题是:如何使用Named Binding策略实现与Ninject 的绑定 ?我不想在我的域类中对容器有任何依赖,所以建议的解决方案对我不起作用

当然没有将ctor更改为IEnumerable<IResolver> - 我想要两个单独的明确命名的参数!

为什么不能通过参数名称定义绑定?例如:

Bind<IResolver>().To<SafeguardedResolver>();
Bind<IResolver>().To<UnsafeResolver>()
    .WhenInjectedInto<SafeguardedResolver>()
    .AsParameter("unsafeResolver");
Bind<IResolver>().To<SafeResolver>()
    .WhenInjectedInto<SafeguardedResolver>()
    .AsParameter("safeResolver");

是否可以通过反射获取参数的名称?

我希望有人可以给我一个答案,如何解决这个问题(也许是通过使用另一个DI框架?)或者为什么这是不可能的。

1 个答案:

答案 0 :(得分:1)

  

我不想在我的域类

中对容器有任何依赖

您可以使用命名绑定而无需引用类库中的容器,以下是您可以执行此操作的方法:

StandardKernel kernel = new StandardKernel();

kernel
    .Bind<IResolver>()
    .To<SafeguardedResolver>()
    .WithConstructorArgument("unsafeResolver", c => c.Kernel.Get<IResolver>("unsafe"))
    .WithConstructorArgument("safeResolver", c => c.Kernel.Get<IResolver>("safe"));

kernel
    .Bind<IResolver>()
    .To<UnsafeResolver>()
    .Named("unsafe")
    .BindingConfiguration.IsImplicit = true;

kernel
    .Bind<IResolver>()
    .To<SafeResolver>()
    .Named("safe")
    .BindingConfiguration.IsImplicit = true;

以下是使用Pure DI执行相同操作的方法:

var result = new SafeguardedResolver(new UnsafeResolver(), new SafeResolver());

在这种情况下,纯粹DI的简单性是IMO it is better than using a container的原因之一。