C# 简单注射器自结合

C# 简单注射器自结合,c#,console-application,simple-injector,constructor-injection,C#,Console Application,Simple Injector,Constructor Injection,我试图学习使用简单注入器的依赖注入,所以我创建了一个简单的程序。我浏览了大量的例子,但没有找到类似的例子。Ninject有一个类似的例子,它们使用 Bind<Samurai>().ToSelf(); 阶级 实现 public class Ferrari : ICar { public void Move(string direction, int distance) { Console.WriteLine("I am driving {0} real

我试图学习使用简单注入器的依赖注入,所以我创建了一个简单的程序。我浏览了大量的例子,但没有找到类似的例子。Ninject有一个类似的例子,它们使用

Bind<Samurai>().ToSelf();
阶级

实现

public class Ferrari : ICar
{
    public void Move(string direction, int distance)
    {
        Console.WriteLine("I am driving {0} really fast for {1} miles", direction, distance);
    }
    public void Stop()
    {
        Console.WriteLine("I am slamming on the brakes because I'm going too fast");
    }
}

public class Lexus : ICar
{
    public void Move(string direction, int distance)
    {
        Console.WriteLine("I am driving {0} for {1} miles", direction, distance);
    }
    public void Stop()
    {
        Console.WriteLine("I am applying the brakes");
    }
}
节目

class Program
{
    static void Main(string[] args)
    {
        var container = new Container();
        container.Options.AllowOverridingRegistrations = true;

        container.Register<ICar, Lexus>();
        container.Register<ICar, Ferrari>();

        container.Verify();

        var johnDoeLexus = new Driver(container.GetInstance<Lexus>());

        johnDoeLexus.Drive("North", 10);
        johnDoeLexus.Brake();

        var johnDoeFerrari = new Driver(container.GetInstance<Ferrari>());

        johnDoeFerrari.Drive("North", 10);
        johnDoeFerrari.Brake();

        Console.ReadLine();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var container=新容器();
container.Options.AllowOverridingRegistrations=true;
container.Register();
container.Register();
container.Verify();
var johnDoeLexus=新驱动程序(container.GetInstance());
约翰多莱克斯大道(“北”,10);
制动器();
var johnDoeFerrari=新驱动程序(container.GetInstance());
约翰多费拉里大道(“北”,10);
制动器();
Console.ReadLine();
}
}

自绑定是简单注入器的隐式行为。因此,像

Bind<Samurai>().ToSelf();
Bind().ToSelf();

对于简单的注入器来说,这是不必要的。

我认为这个问题更重要的是Ninject的
.ToSelf()

Ninject使用
.ToSelf()
作为的更可读版本

kernel.Bind<Samurai>().To<Samurai>();
之所以要执行
.ToSelf()
,是为了继续链接方法,例如定义范围。Ninject具有隐式自绑定,因此您不需要
.ToSelf()
,除非您要定义范围或其他内容:

kernel.Bind<Samurai>().ToSelf().InSingletonScope();

kernel.Bind<Samurai>().ToSelf().InThreadScope()
关于依赖项注入:

您要求的是一辆
雷克萨斯
,而您本应要求的是一辆
ICar

ICar car = container.GetInstance<ICar>()
ICar car=container.GetInstance()
根据您注册的具体类别,您可以决定是要一辆雷克萨斯还是法拉利


在简单注入器中进行自绑定的方法是使用以下注册:

container.Register<Samurai>();
换句话说,您正在注册一辆
ICar
,但您不是在解析一辆
ICar
,而是在解析一辆
Lexus
。由于
雷克萨斯
尚未注册为
t服务
,因此Simple Injector对该类型一无所知,它将为您创建一个新的
雷克萨斯
注册。这与执行此操作相同:

container.Register<ICar, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());
container.Register<ICar, Lexus>();
container.Register<Lexus, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());
您可能希望对
GetInstance
的两个调用都返回相同的(单个)实例,但事实并非如此,因为Simple Injector将为
Lexus
创建一个新的(瞬态)注册,并且每次对
GetInstance
的调用都将创建一个新的
Lexus

还请注意您使用的
AllowOverridingRegistrations
。使用
AllowOverridingRegistrations
在大多数情况下是个坏主意。虽然其他容器允许您通过多次调用
register
来注册相同抽象的一组类型,但Simple Injector不允许这样做。相反,Simple Injector包含用于此目的的
RegisterCollection
方法。例如,登记多辆汽车可以按如下方式进行:

container.RegisterCollection<ICar>(new[] { typeof(Lexus), typeof(Ferrari) });
var cars = container.GetAllInstances<ICar>();
container.RegisterCollection(新[]{typeof(雷克萨斯)、typeof(法拉利)});
您可以按以下方式申请这些车辆:

container.RegisterCollection<ICar>(new[] { typeof(Lexus), typeof(Ferrari) });
var cars = container.GetAllInstances<ICar>();
var cars=container.GetAllInstances();
或者,您可以将汽车集合注入类型为的构造函数中:

public SomeType(IEnumerable<ICar> cars) {
    this.cars = cars;
}
public SomeType(IEnumerable cars){
这个。汽车=汽车;
}
如果您使用
RegisterCollection
注册了一个汽车列表,那么使用
GetInstance
请求一辆汽车将失败,因为Simple Injector不知道应该返回哪些汽车


API采用这种方式,以减少开发人员在仍然编译甚至运行但结果不正确的注册中出错的可能性。使用
AllowOverridingRegistrations
标记容器可以替换已完成的注册。这在容器配置被拆分为多个库并被多个应用程序重用的场景中非常有用。它覆盖了一个已完成的注册。这意味着您将失去以前的注册。大多数情况下,你其实并不想这样。

感谢史蒂文如此彻底。作为对您声明GetInstance将失败的回应,因为它不知道返回哪辆车——此应用程序的设计是否有缺陷(是否可能没有多个实现,例如Lexus、Ferrari)?如果是这样的话,更新这个例子的正确方法是什么,以帮助我学习如何正确地处理程序的设计?谢谢。@mjw06d您显示的代码只是一个玩具应用程序,对此我没什么可说的。很难想象这个ICar接口会有什么有用的业务行为。很难用汽车或武士来证明依赖注入的有效使用。我的建议是在一个真正的原型应用程序上尝试DI和SOLID的概念,你将实际为你的老板构建一个原型应用程序(例如,带有一些业务逻辑的web应用程序),然后回到Stackoverflow,询问该应用程序的设计和该应用程序依赖注入的使用。是的,但建议显式注册所有(根)类型,因为这样可以保留配置和。
container.Register<ICar, Lexus>();
container.Register<Lexus, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());
container.Register<ICar, Lexus>(Lifestyle.Singleton);

var instance1 = container.GetInstance<Lexus>();
var instance2 = container.GetInstance<Lexus>();
container.RegisterCollection<ICar>(new[] { typeof(Lexus), typeof(Ferrari) });
var cars = container.GetAllInstances<ICar>();
public SomeType(IEnumerable<ICar> cars) {
    this.cars = cars;
}