ServiceContainer、IoC 和一次性对象

2024-01-06

我有一个问题,我要标记这个问题主观因为这就是我认为它演变成的,更多的讨论。我希望能有一些好的想法或者一些发人深省的想法。我对这个冗长的问题表示歉意,但你需要了解上下文。

问题基本上是:

  • 您如何处理与 IoC 容器相关的具体类型?具体来说,谁负责处置它们,如果它们需要处置,以及如何将这些知识传播到调用代码?

您是否要求它们是 IDisposable 的?如果不是,该代码是否可以适应未来,或者是不能使用一次性物品的规则?如果您在接口和具体类型上强制执行 IDisposable 要求以确保面向未来,那么谁的责任是作为构造函数调用的一部分注入对象?


Edit: 我接受了答案@克里斯·巴拉德 https://stackoverflow.com/users/18782/chris-ballard因为它是最接近我们最终采用的方法。

基本上,我们总是返回一个如下所示的类型:

public interface IService<T> : IDisposable
    where T: class
{
    T Instance { get; }
    Boolean Success { get; }
    String FailureMessage { get; } // in case Success=false
}

然后,我们从 .Resolve 和 .TryResolve 返回一个实现此接口的对象,以便我们在调用代码中获得的始终是相同的类型。

现在,实现这个接口的对象,IService<T>是 IDisposable,并且应该always被处置。解决服务是否由程序员来决定IService<T>对象是否应该被处置。

然而,无论服务实例是否应该被处置,这是关键的部分,知识被烘焙到实现的对象中IService<T>,所以如果它是一个工厂范围的服务(即每次调用 Resolve 都会得到一个新的服务实例),那么当IService<T>对象被处置。

这也使得支持其他特殊范围成为可能,例如池化。现在我们可以说我们需要最少 2 个服务实例,最多 15 个,通常为 5 个,这意味着每次调用 .Resolve 都会从可用对象池中检索一个服务实例,或者构造一个新的服务实例。然后,当IService<T>持有池化服务的对象被释放,服务实例被释放回其池中。

当然,这使得所有代码看起来像这样:

using (var service = ServiceContainer.Global.Resolve<ISomeService>())
{
    service.Instance.DoSomething();
}

但这是一种干净的方法,并且无论使用哪种服务或具体对象,它都具有相同的语法,因此我们选择它作为可接受的解决方案。


最初的问题如下,供后代使用


冗长的问题来了:

我们有一个使用的 IoC 容器,最近我们发现了一个问题。

在非 IoC 代码中,当我们想要使用文件时,我们使用这样的类:

using (Stream stream = new FileStream(...))
{
    ...
}

毫无疑问,这个类是否持有有限的资源,因为我们知道文件必须关闭,并且该类本身实现了 IDisposable。规则很简单,我们构造的每个实现 IDisposable 的对象的类都必须被丢弃。无话可问。此类的用户不能决定调用 Dispose 是否是可选的。

好的,接下来是 IoC 容器的第一步。假设我们不希望代码直接与文件对话,而是通过一层间接的方式。在本示例中,我们将此类称为 BinaryDataProvider。在内部,该类使用流,它仍然是一次性对象,因此上面的代码将更改为:

using (BinaryDataProvider provider = new BinaryDataProvider(...))
{
    ...
}

这并没有太大改变。类实现IDisposable的知识还在这里,没有问题,我们需要调用Dispose。

但是,假设我们有提供数据的类,但目前不使用任何此类有限的资源。

上面的代码可以写成:

BinaryDataProvider provider = new BinaryDataProvider();
...

好的,到目前为止一切顺利,但问题的核心来了。假设我们想要使用 IoC 容器来注入此提供程序,而不是依赖于特定的具体类型。

代码将是:

IBinaryDataProvider provider =
    ServiceContainer.Global.Resolve<IBinaryDataProvider>();
...

请注意,我假设有一个独立的接口可用,我们可以通过它访问该对象。

通过上述更改,如果我们稍后想要使用真正应该处理的对象怎么办?解析该接口的现有代码都不是为了处理该对象而编写的,那么现在怎么办?

从我们的角度来看,我们必须选择一种解决方案:

  • 实现运行时检查,检查正在注册的具体类型是否实现 IDisposable,并要求其公开的接口也实现 IDisposable。这不是一个好的解决方案
  • 对所使用的接口进行约束,它们必须始终继承自 IDisposable,以便面向未来
  • 强制运行时,任何具体类型都不能是 IDisposable,因为这不是由使用 IoC 容器的代码专门处理的
  • 只需让程序员检查该对象是否实现 IDisposable 并“做正确的事情”?
  • 还有其他人吗?

另外,在构造函数中注入对象怎么样?我们的容器以及我们研究过的其他一些容器能够将新对象注入到具体类型的构造函数的参数中。例如,如果我们的BinaryDataProvider需要一个实现的对象ILogging接口,如果我们对这些对象强制执行 IDispose-“能力”,谁的责任是处置日志记录对象?

你怎么认为?我想要意见,好的和坏的。


一种选择可能是使用工厂模式,这样由 IoC 容器直接创建的对象永远不需要自行处理,例如

IBinaryDataProviderFactory factory =
    ServiceContainer.Global.Resolve<IBinaryDataProviderFactory>();
using(IBinaryDataProvider provider = factory.CreateProvider())
{
    ...
}

缺点是增加了复杂性,但这确实意味着容器永远不会创建开发人员应该处理的任何东西 - 它始终是执行此操作的显式代码。

如果你真的想让它显而易见,工厂方法可以命名为类似 CreateDisposableProvider() 的名称。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ServiceContainer、IoC 和一次性对象 的相关文章

随机推荐

  • 如何编写 CSS 选择器来选择不具有特定属性的元素?

    如何编写 CSS 选择器来选择不具有特定属性的元素 我有2个 div 节点如下 First div class weEq5 div div
  • Chrome 时间线 - 如何确定“重新计算样式”日志条目的原因?

    使用 Chrome 中的内置时间线记录器分析页面时 我看到重复的 重新计算样式 条目 它们没有明显的信息将它们链接到 DOM 元素或事件 我怎样才能最好地确定这些条目的原因 已发布的用于调查的 jQuery 版本的替代方案是控制台中的简单一
  • 为什么会出现 TypeError: 'str' object不能被解释为整数?

    我正在做OrderedDict的练习 我正在尝试使用 input rsplit 方法为字典分配值 发生了一个错误 名为 TypeError str 对象无法解释为整数 我哪里搞错了 from collections import Order
  • 在生产环境中使用代码优先降级(回滚)数据库

    我有一个网络应用程序 安装在客户的计算机上供他们内部使用 我使用 C MVC5 和代码优先的实体框架 我使用了自动迁移 true 但我停止并将其设置为 false 我将其安装在生产环境 发行版 上 使用部署包 无 Visual Studio
  • TailwindCSS中的transition-all和transition有什么区别

    Tailwind 提供了多个实用程序来控制 CSS 属性转换 其中有transition and transition all 我检查了这两个类的 CSS 属性 这里它们的顺序相同 transition property backgroun
  • 检测声音是否在 Selenium 中播放

    我在我正在开发的项目的 iframe 中加载了一些第三方网站 但我需要以某种方式检测这些网站是否正在播放任何声音 我没有看到任何使用 WebDriver 的方法来查看浏览器中是否正在播放声音 是否有其他方法来查询虚拟机本身 在现代 HTML
  • 如何通过 decltype 声明迭代器的值

    在 C 98 中 我通常使用以下代码来声明迭代器值类型中的变量 typename std iterator traits
  • 在 python 中对局部变量使用显式 del

    使用显式的最佳实践和建议是什么delpython 中的语句 我知道它用于删除属性或字典 列表元素等 但有时我看到它在代码中的局部变量上使用 如下所示 def action x result None something produce so
  • Go数组初始化

    func identityMat4 16 float return 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 我希望你能从这个例子中明白我想要做什么 我如何在 Go 中执行此操作 func identityMat4 1
  • 递增:x++ 与 x += 1

    我读到 为了清楚起见 许多开发人员使用 x 1 而不是 x 我知道 x 对于新开发人员来说可能会含糊不清 而 x 1 总是更清晰 但是两者之间的效率有什么区别吗 使用 for 循环的示例 for x 0 x lt 1000 x 1 vs f
  • 在Python中删除文件行

    我正在尝试创建一个接受用户名和高分的程序 如果他们已经是用户 他们会更新到新的高分 或者如果不是 则仅添加高分 我的代码是 try a open data r except FileNotFoundError a open data w a
  • 有没有办法允许用户从网站复制文本,并且文本不格式化?

    几乎只是一个问题 我有一个客户要求在整个网页上使用几乎白色文本的负片设计 但测试人员表示 从网站复制和粘贴很烦人 因为复制到 Word 等内容时 所有内容都显示为白色文本 当用户尝试从网站复制文本时 是否有办法预先删除格式 或者有没有办法劫
  • javax.servlet.http.Cookie 的 getDomain() 返回 null

    如何获取 cookie 的实际域 getDomain getPath 返回 null 我也设置了适当的值 我正在使用response addCookie cookie 提前致谢 问候 普拉尚特 饼干来了in从浏览器可能没有可用的数据 只有
  • Spring Hibernate 模板何时使用以及为什么?

    问候 目前正在开发小型 Web 服务应用程序 其中来自 Web 服务 使用 CXF Spring 的响应被处理并保存到数据库 为了使用数据库 我使用 Hibernate 3 5 在网上浏览一些Hibernate Spring的例子 我经常可
  • 部署 Apache Camel 应用程序时出现警告

    当我将应用程序部署到 GlassFish 时 我看到以下警告 WARN AnnotationTypeConverterLoader Ignoring converter type org apache activemq camel conv
  • valgrind 在使用 libcurl 时检测内存泄漏(无 ssl)

    在我的 C 程序中 我使用 libcurl 的一些基本函数 今天我运行 valgrind 来检查是否存在内存泄漏 并且 valgrind 疯狂地报告了多个错误 我基本上追踪到 CURL curl CURLcode res curl curl
  • 当实体包含 UUID 时,H2 数据库的 Hibernate 数据库模式验证失败

    For a H2数据库架构映射到具有 UUID 的实体 the Hibernate ddl 验证失败与例外 根本原因 org hibernate tool schema spi SchemaManagementException 架构验证
  • HTML5异步文件上传,上传流始终无效

    我正在尝试调试我不久前构建的异步文件上传器 它不再工作 我已经花了很多时间但没有成功 服务器接收的流总是损坏 事实上我保存的文件 图像 无法打开 为了简化调试 我设置了一个全新的 ASP NET 项目 其中包含两个主要文件 带有表单字段的
  • 连接到 Redis 127.0.0.1:6379 时出错 (Errno::ECONNREFUSED) - Wercker

    我正在使用 wercker 来运行我的 Rails 应用程序的规范 我在 wercker 上设置 redis 时遇到问题 在我的 Rails 应用程序中我有redis rb看起来像这样 if Figaro env rediscloud ur
  • ServiceContainer、IoC 和一次性对象

    我有一个问题 我要标记这个问题主观因为这就是我认为它演变成的 更多的讨论 我希望能有一些好的想法或者一些发人深省的想法 我对这个冗长的问题表示歉意 但你需要了解上下文 问题基本上是 您如何处理与 IoC 容器相关的具体类型 具体来说 谁负责