在 Simple Injector 中注册时设置收集项目的 Lifestyle
Setting Lifestyle of collection items during registration in Simple Injector
Container.Collection.Register
似乎没有需要 Lifestyle
的重载。所有发现的实现都将注册为默认 Lifestyle
。省略这种过载的原因是什么?
添加一个集合的首选方法是什么,其中所有项目都应该有一个不是默认生活方式的 Lifestyle
?
What is the reasoning behind the omission of such an overload?
首先,因为,(如Eric Lippert stated):
no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost
其次,接受 Type
实例列表的 Collection.Register
重载(例如 Collection.Register<TService>(params Type[])
),接受实现和抽象的列表。为抽象提供 Lifestyle
没有多大意义,甚至令人困惑。
要了解为什么 Simple Injector 允许提供抽象,请查看以下注册:
container.Collection.Register<ILogger>(
typeof(ILogger),
typeof(ISpecialLogger),
typeof(SqlLogger));
container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
在这个例子中,注册了一个记录器集合,其中两个提供的类型是抽象的。允许提供抽象背后的想法是,有了它,您可以将它们指向其他注册。这正是前面示例所做的。解析记录器集合时,它将由 Scoped
DefaultLogger
、Singleton
SpecialLogger
和 Transient
SqlLogger
.
现在考虑一个假设的新 Collection.Register
重载,它接受 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);
所有元素都是Transient
,而其中两个元素指向不同生活方式的注册是什么意思?
我们还没有找到解决这些问题的好方法 API(目前),这就是为什么容器没有这样的重载。
What is the preferred way of adding a collection where all items should have a Lifestyle that is not the default lifestyle?
有多种方法可以做到这一点。
选项 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);
当 Simple Injector 首次解析 IEnumerable<ILogger>
时,对于每个元素它将(按以下顺序):
- 尝试获取显式注册的具体注册(示例中:
Register<SqlLogger>
- 尝试使用未注册的类型解析获取该注册
- 尝试在使用配置的
Container.Options.LifestyleSelectionBehavior
(默认为 Transient
)的同时自行创建注册。
选项 2:使用 Register(Type, IEnumerable) 重载
除了向 Collection.Register
提供类型或程序集的列表之外,您还可以提供 Registration
实例的列表。 Registration
描述了为特定生活方式创建特定组件,当您调用 Container.Register
或 Container.Collection.Register
时,简单注入在内部使用此 class。但您也可以手动创建 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));
这会强制集合的所有注册类型都具有 Transient
生活方式。如果需要,您还可以为每种类型赋予其特定的生活方式。
选项 3:覆盖 LifestyleSelectionBehavior
当找不到注册时,Collection.Register
会在最后一分钟使用配置的 LifestyleSelectionBehavior
自行注册。默认选择行为总是 returns Lifestyle.Transient
,但可以更改此行为。例如:
class CustomLifestyleSelectionBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType) =>
implementationType == typeof(SqlLogger)
? Lifestyle.Singleton
: Lifestyle.Transient;
}
这个实现显然有点天真,但展示了这个概念。您可以按如下方式覆盖默认行为:
container.Options.LifestyleSelectionBehavior =
new CustomLifestyleSelectionBehavior();
选项 4:追加
在Collection.Register
之后,可以一次注册所有元素,您可以使用Collection.Append
方法。它们允许 one-by-one 注册集合元素:
container.Collection.Append<ILogger, SqlLogger>(Lifestyle.Singleton);
container.Collection.Append<ILogger, FileLogger>(Lifestyle.Transient);
还有 non-generic 重载可用,它简化了 auto-registering 这些类型,例如当使用 Container.GetTypesToRegister
.
返回时
这些是您在 Simple Injector v4.6 中的基本选项。我们可能会决定在将来添加一个方便的 Collection.Register<T>(IEnumerable<Type>, Lifestyle)
重载,因为这个重载的省略确实会不时引起一些混乱。
Container.Collection.Register
似乎没有需要 Lifestyle
的重载。所有发现的实现都将注册为默认 Lifestyle
。省略这种过载的原因是什么?
添加一个集合的首选方法是什么,其中所有项目都应该有一个不是默认生活方式的 Lifestyle
?
What is the reasoning behind the omission of such an overload?
首先,因为,(如Eric Lippert stated):
no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen. All of them cost
其次,接受 Type
实例列表的 Collection.Register
重载(例如 Collection.Register<TService>(params Type[])
),接受实现和抽象的列表。为抽象提供 Lifestyle
没有多大意义,甚至令人困惑。
要了解为什么 Simple Injector 允许提供抽象,请查看以下注册:
container.Collection.Register<ILogger>(
typeof(ILogger),
typeof(ISpecialLogger),
typeof(SqlLogger));
container.Register<ILogger, DefaultLogger>(Lifestyle.Scoped);
container.Register<ISpecialLogger, SpecialLogger>(Lifestyle.Singleton);
在这个例子中,注册了一个记录器集合,其中两个提供的类型是抽象的。允许提供抽象背后的想法是,有了它,您可以将它们指向其他注册。这正是前面示例所做的。解析记录器集合时,它将由 Scoped
DefaultLogger
、Singleton
SpecialLogger
和 Transient
SqlLogger
.
现在考虑一个假设的新 Collection.Register
重载,它接受 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);
所有元素都是Transient
,而其中两个元素指向不同生活方式的注册是什么意思?
我们还没有找到解决这些问题的好方法 API(目前),这就是为什么容器没有这样的重载。
What is the preferred way of adding a collection where all items should have a Lifestyle that is not the default lifestyle?
有多种方法可以做到这一点。
选项 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);
当 Simple Injector 首次解析 IEnumerable<ILogger>
时,对于每个元素它将(按以下顺序):
- 尝试获取显式注册的具体注册(示例中:
Register<SqlLogger>
- 尝试使用未注册的类型解析获取该注册
- 尝试在使用配置的
Container.Options.LifestyleSelectionBehavior
(默认为Transient
)的同时自行创建注册。
选项 2:使用 Register(Type, IEnumerable) 重载
除了向 Collection.Register
提供类型或程序集的列表之外,您还可以提供 Registration
实例的列表。 Registration
描述了为特定生活方式创建特定组件,当您调用 Container.Register
或 Container.Collection.Register
时,简单注入在内部使用此 class。但您也可以手动创建 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));
这会强制集合的所有注册类型都具有 Transient
生活方式。如果需要,您还可以为每种类型赋予其特定的生活方式。
选项 3:覆盖 LifestyleSelectionBehavior
当找不到注册时,Collection.Register
会在最后一分钟使用配置的 LifestyleSelectionBehavior
自行注册。默认选择行为总是 returns Lifestyle.Transient
,但可以更改此行为。例如:
class CustomLifestyleSelectionBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType) =>
implementationType == typeof(SqlLogger)
? Lifestyle.Singleton
: Lifestyle.Transient;
}
这个实现显然有点天真,但展示了这个概念。您可以按如下方式覆盖默认行为:
container.Options.LifestyleSelectionBehavior =
new CustomLifestyleSelectionBehavior();
选项 4:追加
在Collection.Register
之后,可以一次注册所有元素,您可以使用Collection.Append
方法。它们允许 one-by-one 注册集合元素:
container.Collection.Append<ILogger, SqlLogger>(Lifestyle.Singleton);
container.Collection.Append<ILogger, FileLogger>(Lifestyle.Transient);
还有 non-generic 重载可用,它简化了 auto-registering 这些类型,例如当使用 Container.GetTypesToRegister
.
这些是您在 Simple Injector v4.6 中的基本选项。我们可能会决定在将来添加一个方便的 Collection.Register<T>(IEnumerable<Type>, Lifestyle)
重载,因为这个重载的省略确实会不时引起一些混乱。