在 Simple Injector 中注册期间设置收集项目的生活方式

Aro*_*thu 4 .net c# dependency-injection ioc-container simple-injector

似乎Container.Collection.Register没有重载需要一个Lifestyle. 所有发现的实现都将注册为默认的Lifestyle. 省略这种重载背后的原因是什么?

添加一个集合的首选方式是什么,其中所有项目都应该有一个Lifestyle不是默认的生活方式?

Ste*_*ven 7

省略这种重载背后的原因是什么?

首先,因为,(正如埃里克·利珀特所说):

没有人设计、指定、实施、测试、记录和发布该功能。所有这六件事都是使功能发生所必需的。都是成本

其次,Collection.Register接受Type实例列表(例如Collection.Register<TService>(params Type[]))的重载接受实现和抽象的列表。Lifestyle为抽象提供 a没有多大意义,甚至令人困惑。

要了解为什么 Simple Injector 允许提供抽象,请查看以下注册:

container.Collection.Register<ILogger>(
    typeof(ILogger),
    typeof(ISpecialLogger),
    typeof(SqlLogger));

container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
Run Code Online (Sandbox Code Playgroud)

在这个例子中,注册了一个记录器集合,其中提供的两个类型是抽象的。允许提供抽象背后的想法是,通过它,您可以将它们指向其他注册。这正是前面的例子所做的。当解决伐木工人的集合,它将包括的Scoped DefaultLogger,在Singleton SpecialLoggerTransient SqlLogger

现在考虑一个假设的新Collection.Register重载,它接受 a Lifestyle

container.Collection.Register<ILogger>(new[]
    {
        typeof(ILogger),
        typeof(ISpecialLogger),
        typeof(SqlLogger)
    },
    Lifestyle.Transient);

container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
Run Code Online (Sandbox Code Playgroud)

拥有所有元素是什么意思Transient,而其中两个元素指向不同生活方式的注册?

我们还没有找到一个好的 API 来解决这些问题(还),这就是容器缺乏这种过载的原因。

添加一个集合的首选方式是什么,其中所有项目都应该具有不是默认生活方式的生活方式?

有多种方法可以做到这一点。

选项 1:显式注册元素

在 Simple Injector 中注册的集合使用回退机制来确定他们的生活方式。这是通过检查是否存在集合元素的具体注册来完成的。例如:

container.Collection.Register<ILogger>(typeof(SqlLogger), typeof(FileLogger));

// Ensures that SqlLogger is a Singleton when part of the IEnumerable<ILogger>.
container.Register<SqlLogger>(Lifestyle.Singleton);
Run Code Online (Sandbox Code Playgroud)

IEnumerable<ILogger>Simple Injector 首次解析时,对于每个元素,它将(按以下顺序):

  • 尝试获取显式注册的具体注册(在示例中: Register<SqlLogger>
  • 尝试使用未注册的类型解析获得该注册
  • 尝试在使用配置Container.Options.LifestyleSelectionBehavior(默认为Transient)的同时创建注册本身。

选项 2:使用 Register(Type, IEnumerable<Registration>) 重载

除了向 提供类型或程序集列表之外Collection.Register,您还可以提供Registration实例列表。ARegistration描述了为特定生活方式创建特定组件,当您调用Container.Register或时,此类由简单注入内部使用Container.Collection.Register。但是您也可以Registration手动创建实例并将它们提供给Collection.Register重载,如下所示:

// Load the list of types without registering them
Type[] types = container.GetTypesToRegister<ILogger>(assemblies);

// Register them using the overload that takes in a list of Registrations
container.Collection.Register<ILogger>(
    from type in types
    select Lifestyle.Transient.CreateRegistration(type, container));
Run Code Online (Sandbox Code Playgroud)

这迫使集合的所有注册类型都具有Transient生活方式。如果您愿意,您还可以为每种类型赋予其特定的生活方式。

选项 3:覆盖 LifestyleSelectionBehavior

当找不到注册时Collection.Register,使用配置的LifestyleSelectionBehavior. 默认选择行为始终返回Lifestyle.Transient,但可以更改此行为。例如:

class CustomLifestyleSelectionBehavior : ILifestyleSelectionBehavior
{
    public Lifestyle SelectLifestyle(Type implementationType) =>
        implementationType == typeof(SqlLogger)
            ? Lifestyle.Singleton
            : Lifestyle.Transient;
}
Run Code Online (Sandbox Code Playgroud)

显然,这个实现有点幼稚,但显示了这个概念。您可以按如下方式覆盖默认行为:

container.Options.LifestyleSelectionBehavior =
    new CustomLifestyleSelectionBehavior();
Run Code Online (Sandbox Code Playgroud)

选项 4:附加

Collection.Register允许一次性注册所有元素的旁边,您可以使用这些Collection.Append方法。它们允许一对一注册集合元素:

container.Collection.Append<ILogger, SqlLogger>(Lifestyle.Singleton);
container.Collection.Append<ILogger, FileLogger>(Lifestyle.Transient);
Run Code Online (Sandbox Code Playgroud)

还有非泛型重载可用,它们简化了这些类型的自动注册,例如当使用 返回时Container.GetTypesToRegister

这些是 Simple Injector v4.6 中的基本选项。我们可能会决定Collection.Register<T>(IEnumerable<Type>, Lifestyle)在未来添加一个方便的重载,因为忽略这个重载确实会不时引起一些混乱。