警告,很长的帖子。

最近我对此进行了很多思考,并且在这里努力寻找令人满意的解决方案。我将使用C#和autofac作为示例。

问题

IoC非常适合构建大型的无状态服务树。我解析服务,并将数据仅传递给方法调用。很好。

有时,我想将数据参数传递到服务的构造函数中。那就是工厂的目的。我没有解析服务,而是解析其工厂,并使用参数调用create方法来获取服务。多做点事,但是还可以。

我不时希望我的服务在一定范围内解析为同一实例。 Autofac提供了非常方便的InstancePerLifeTimeScope()。它使我能够始终解析到执行子树中的同一实例。好。

有时候我想将两种方法结合起来。我想要构造函数中的数据参数,并具有实例范围。我还没有找到令人满意的方法来实现这一目标。

解决方案

1。初始化方法

与其将数据传递给构造函数,不如将其传递给Initialize方法。

界面: 通用标签

班级 通用标签

注册: 通用标签

用法: 通用标签

第一次解析服务并调用Initialize之后,我可以在相同的上下文中高兴地解析并获得相同的初始化实例。我不喜欢在调用Initialize之前有一个无法使用的对象。在我调用Initialize()之前,实例可能会被解析并在其他地方使用。

2。持有人模式

这是一个保留对数据对象的引用的模式,而不是注入数据对象本身,而是注入了持有者对象。

接口: 通用标签

班级 通用标签

注册: 通用标签

用法: 通用标签

当我将持有实例的职责移到另一个类时,这会更好一些。我现在也可以在其他服务中使用该支架。另一个好处是,如有必要,我可以在保持器中热交换数据。我不喜欢这样的事实,它会混淆代码并添加我在测试过程中必须模拟的另一个接口。

3。让容器保存实例

界面: 通用标签

班级 通用标签

注册: 通用标签

用法: 通用标签

是的。我不会在任何地方存储工厂调用的结果,因为autofac会为我存储它。这对于任何阅读该代码的人来说都是非常令人惊讶的。我不确定autofac是否打算像这样使用。这样做的好处是我不需要额外的初始化方法或类来保存实例。

问题

您对此有何看法?如何使用运行时数据参数和生存期范围来处理情况?我是否缺少更好的方法?

有帮助吗?

解决方案

Autofac现在可以使用生命周期作用域的扩展来支持该功能。BeginLifetimeScope()方法有一个重载,该重载采用了Action<ContainerBuilder>,该代码允许添加仅针对该生存期范围的新注册。因此,对于给定的示例,它看起来像: 通用标签

其他提示

大多数时候,运行时数据是您在任何过程中都需要传递的非静态信息,例如数学函数中的x,因此处理该数据的最简单方法是在函数中使用参数: 通用标签

但是,假设您的示例只是一个示例,您在问,因为您的类需要保留运行时数据以运行更多进程,并且您不想在每个函数中传递相同的参数:

1.-如果您不放松每个Resolve中运行时数据的范围,则可以使用TypedParameter进行解析:

Ej: 通用标签

2.-如果您要解析的每个地方都没有对运行时数据的引用,则可以 RegisterInstance 。由于直接依赖政策 通用标签

我认为这是您所做的尽可能多的事情。我唯一遇到的麻烦是Autofac在帮助您管理这些生命周期范围方面确实做得并不出色,因此您不得不在某个地方调用它们的BeginLifetimeScope它们可以嵌套“头脑狂。”

另一方面,Ninject做了一些很酷的事情,不需要把脑袋翻过来。他们的命名范围扩展名使您可以创建( gasp )命名作用域,并绑定该作用域内对象的生命周期。如果您正在使用工厂(显然是从问题上判断),则还需要使用上下文保存扩展,以便从工厂中激活的内容可以从在其中激活工厂的命名范围获得生命周期管理。绑定结束看起来像这样: 通用标签

与此相关的一个好地方是,这些绑定的作用域是专门绑定到命名作用域的,而不是仅仅绑定到链上最近的生命周期作用域。恕我直言,它使这些对象的寿命更加可预测。

许多IoC框架都支持工厂功能(或lambda表达式)的注册,该功能将容器/作用域/解析上下文本身的实例作为其自变量之一。

这允许使用其他间接级别,以及使用唯一标识上下文或范围的信息。另外,许多提供钩子,例如事件处理程序或从生命周期范围类派生的选项,可以与正在启动或结束的范围进行交互。

原理

对于AutoFac和您的特定示例,以下原则将起作用,并在注册中使用附加级别的间接访问。 通用标签

我们可以在上下文/范围内使用任何可用的唯一属性来构造此映射。 通用标签

我们可以像这样使用它来提供“本地”数据实例,以将它们注入我们的范围服务实例中。 通用标签

下面是一个更完整,更通用的AutoFac示例。

此模式的通用扩展类 通用标签

允许以下语法进行注册: 通用标签

并像这样解决 通用标签

更简单的选择

如果您显式启动嵌套作用域,并且在这样做的时候就知道如何创建作用域的Data实例,则可以跳过扩展类,并在创建嵌套作用域时注册“ factory”委托给嵌套作用域: 通用标签

如果我对您的理解正确,那么您想通过将对象创建委托给容器来使用工厂,同时将一些参数传递给其构造函数。

这在温莎城堡中使用类型化的工厂设施来实现

我们要解析的示例类: 通用标签

我们创建一个工厂界面: 通用标签

我们将不会实现此接口,因为Castle Windsor将使用动态代理生成一个实现。这里有一个重要的细节:工厂方法中的参数名称(数据)与构造函数中的参数名称应匹配。

然后我们进行注册并尝试解析这些值。 通用标签

您将看到在相同范围内创建的对象是相同的引用。让我知道这是否是您想要的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top