使用Simple Injector进行自我绑定

4 c# console-application constructor-injection simple-injector

我正在尝试使用Simple Injector学习依赖注入,所以我创建了一个简单的程序.我查看了大量的例子,但没有找到类似的东西.Ninject有一个类似的例子,他们使用实现自我绑定实现

Bind<Samurai>().ToSelf();
Run Code Online (Sandbox Code Playgroud)

但我没有在简单的注射器中找到任何自我约束的例子.目前该程序运行良好,我得到了我正在寻找的预期结果,但这是正确的方法吗?该程序是最后一个代码示例.

接口

public interface ICar
{
    void Move(string direction, int distance);
    void Stop();
}
Run Code Online (Sandbox Code Playgroud)

public class Driver
{
    private readonly ICar _car = null;

    public Driver(ICar car)
    {
        this._car = car;
    }

    public void Drive(string direction, int distance)
    {
        _car.Move(direction, distance);
    }

    public void Brake()
    {
        _car.Stop();
    }
}
Run Code Online (Sandbox Code Playgroud)

实现

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

程序

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

Ste*_*ven 11

在Simple Injector中进行自我绑定的方法是使用以下注册:

container.Register<Samurai>();
Run Code Online (Sandbox Code Playgroud)

这是一个捷径:

container.Register<Samurai, Samurai>();
Run Code Online (Sandbox Code Playgroud)

这又是一个捷径:

container.Register<Samurai, Samurai>(Lifestyle.Transient);
Run Code Online (Sandbox Code Playgroud)

当调用Register<TService, TImplementation>.您基本上要求容器是TImplementation每次TService请求时创建的.

然而,简单注入器可以在Samurai没有显式注册的情况下解析具体类型(例如您的),但在大多数情况下,最好显式注册所有类型(或至少通过调用直接从容器请求的所有类型GetInstance<Something>()).通过注册该类型,您可以让Simple Injector知道您要解决它,这允许Simple Injector验证它是否可以被解析(在调用时Verify()),并允许Simple Injector 对该类型进行诊断分析.

请注意,虽然电话GetInstance<TService>会要求注册TService.在你的代码中你这样做:

container.Register<ICar, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());
Run Code Online (Sandbox Code Playgroud)

换句话说,你正在注册ICar,但你没有解决ICar,你正在解决一个问题Lexus.由于Lexus尚未注册TService,Simple Injector对该类型一无所知,因此只需为此创建一个新的注册Lexus.这与执行此操作相同:

container.Register<ICar, Lexus>();
container.Register<Lexus, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());
Run Code Online (Sandbox Code Playgroud)

这可能会有问题,因为您可能打算ICar采用不同的生活方式:

container.Register<ICar, Lexus>(Lifestyle.Singleton);

var instance1 = container.GetInstance<Lexus>();
var instance2 = container.GetInstance<Lexus>();
Run Code Online (Sandbox Code Playgroud)

您可能希望两个调用都GetInstance返回相同的(单个)实例,但事实并非如此,因为Simple Injector将为每个调用创建一个新的(瞬态)注册Lexus,并且会创建一个新的.LexusGetInstance

另请注意您的使用者AllowOverridingRegistrations.使用AllowOverridingRegistrations大部分时间都是个坏主意.虽然其他容器允许您通过Register多次调用来注册一组相同抽象类型,但Simple Injector不允许这样做.相反,Simple Injector包含一个RegisterCollection方法.例如,注册多辆汽车可以按如下方式进行:

container.RegisterCollection<ICar>(new[] { typeof(Lexus), typeof(Ferrari) });
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式申请这些车辆:

var cars = container.GetAllInstances<ICar>();
Run Code Online (Sandbox Code Playgroud)

或者您可以将一组汽车注入到类型的构造函数中:

public SomeType(IEnumerable<ICar> cars) {
    this.cars = cars;
}
Run Code Online (Sandbox Code Playgroud)

如果你注册了一个汽车列表然后使用RegisterCollection,请求使用一辆汽车GetInstance<ICar>将失败,因为Simple Injector不知道它应该返回哪些汽车.

API是以这种方式显式设计的,以使开发人员在注册中仍然不太可能编译甚至运行错误,但结果不正确.标记容器AllowOverridingRegistrations允许替换已进行的注册.这在容器的配置被拆分为多个库并由多个应用程序重用的情况下非常有用.它会覆盖已进行的注册.这意味着您将放弃此之前的注册.大多数时候你实际上并不想要这个.