有没有一种简单的方法可以将所有可用类型绑定到一个具体实例

Is there an easy way to bind all available types to a concrete instance

我有以下接口和具体实现:

interface IFoo {
      string Name { get ;}
}

class Foo :IFoo{
     public string Name { get; set; }
}

interface IBar {
     string Name { get; }
}

class Bar : IBar {
     public string Name { get;set;}

     public Bar(Foo foo) {

     }
}

在class构造函数中可以看到Bar对Foo有依赖关系

这些是我的绑定:

kernel.Bind<IFoo>().ToConstant(new Foo() { Name="Foo"; });
kernel.Bind<IBar>().To<Bar>();

当我使用 kernel.Get 并请求 Bar 时,没有错误,但是 Foo 依赖项是我最初绑定的 Foo 的不同实例。当我检查 Bar 构造函数中的 Foo 实例时,我希望看到名称为 "Foo" 的 Foo,但我看到的却是 Foo { Name = null }.

当我绑定到具体的 Foo 时,一切都按预期工作:

var foo = new Foo() { Name="Foo" };
kernel.Bind<IFoo>().ToConstant(foo);
kernel.Bind<Foo>().ToConstant(foo);
kernel.Bind<IBar>().To<Bar>();

var bar= kernel.Get<Bar>(); // works! foo has name "Foo"

有没有方便的方法将 Foo 的特定实例绑定到所有可用接口和具体类型?

例如:

class ConcreteFoo : AbstractFoo, IFoo {
   ...
}

var foo = new Foo();
kernel.Bind<IFoo>().ToConstant(foo);
kernel.Bind<AbstractFoo>().ToConstant(foo);
kernel.Bind<ConcreteFoo>().ToConstant(foo);

我有一个通用框架。框架之外是客户定义的 Foo 和 Bar。我希望客户能够灵活地在 Bar 构造函数中指定 IFoo 或 Foo 。如果构造函数被定义为 Bar(IFoo),客户端可能无论如何都会将其转换为 Foo。

ninject 没有提供此类功能。 ninject 提供的是绑定到多种类型,例如:

Bind<IFoo,Foo>().To<Foo>().InSingletonScope();

确保无论请求 IFooFoo 的什么组合,您总是得到相同的 Foo 实例。

然后,Ninject.Extensions.Conventions 可以查找类型(就像一个程序集的所有 类)并将它们绑定到它们所有的接口、它们所有的基类型,...但只能是 or , 不是都。你可以用它来实现你想要的,但它也需要你的代码,..而且有点尴尬。

所以,在我看来,最好自己动手:

using Ninject.Infrastructure.Language;

public static void RegisterConstantAsAllTypes(IBindingRoot bindingRoot, object instance)
{
    Type t = instance.GetType();

    IEnumerable<Type> typesToBind = t.GetAllBaseTypes()
        .Concat(t.GetInterfaces())
        .Except(new[] { typeof(object) });

    bindingRoot
        .Bind(typesToBind.ToArray())
        .ToConstant(instance);
}

根据您的示例,以下测试通过:

[Fact]
public void FactMethodName()
{
    var kernel = new StandardKernel();
    var foo = new Foo();
    RegisterConstantAsAllTypes(kernel, foo);

    kernel.Get<IFoo>().Should().Be(foo);
    kernel.Get<Foo>().Should().Be(foo);
    kernel.Get<AbstractFoo>().Should().Be(foo);
}