问题标签 [idisposable]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
1082 浏览

inversion-of-control - ServiceContainer、IoC 和一次性对象

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

问题基本上是:

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

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


编辑:我接受了@Chris Ballard的答案,因为它与我们最终采用的方法最接近。

基本上,我们总是返回一个看起来像这样的类型:

然后我们从 .Resolve 和 .TryResolve 返回一个实现这个接口的对象,这样我们在调用代码中得到的总是相同的类型。

现在,实现此接口的对象IService<T>是 IDisposable 的,并且应该始终被释放。解决服务的程序员不能决定是否IService<T>应该释放对象。

然而,这是关键部分,无论服务实例是否应该被释放,这些知识都被嵌入到实现的对象IService<T>中,所以如果它是一个工厂范围的服务(即每次调用 Resolve 最终都会得到一个新的服务实例),那么服务实例会在IService<T>对象被释放的时候被释放。

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

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

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


原始问题如下,供后代使用


冗长的问题来了:

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

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

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

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

这变化不大。类实现IDisposable的知识还在,不问,需要调用Dispose。

但是,让我们假设我们的类提供的数据现在不使用任何有限的资源。

那么上面的代码可以写成:

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

代码将是:

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

有了上面的改动,如果我们以后想要使用一个真正应该被处理掉的对象怎么办?解析该接口的现有代码都没有被编写来处理该对象,那么现在怎么办?

在我们看来,我们必须选择一种解决方案:

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

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

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

0 投票
3 回答
968 浏览

c# - 调用 Icon.ToBitmap() 后处理 Icon 是否安全?

调用System.Drawing.Icon.ToBitmap()创建图像后,处置原件是否安全Icon

0 投票
6 回答
1407 浏览

.net - 如何管理缓存的 IDisposable 对象?

我有一个创建成本很高的对象,它使用一些非托管资源,这些资源在完成后必须显式释放,因此实现 IDisposable()。我想要一个缓存这些昂贵资源的实例,以便最大限度地降低创建成本,但我不知道如何处理处置。

如果使用对象的方法负责处置,那么我最终会在缓存中处置实例,然后必须重新创建这些实例,从而破坏缓存点。如果我不在使用它们的方法中处置对象,那么它们永远不会被处置。我以为当它们从缓存中取出时我可以处理它们,但是我最终可能会处理一个仍在被方法使用的实例。

让它们超出范围并被垃圾收集器收集并在那时释放资源是否有效?这感觉是错误的,并且反对他们一次性的想法......

0 投票
8 回答
6421 浏览

c# - 您是否应该实现 IDisposable.Dispose() 以便它永远不会抛出?

对于 C++ 中的等效机制(析构函数),建议它通常不应该抛出任何异常。这主要是因为这样做你可能会终止你的进程,这很少是一个好的策略。

在 .NET 中的等效场景中...

  1. 抛出第一个异常
  2. 由于第一个异常而执行 finally 块
  3. finally 块调用 Dispose() 方法
  4. Dispose() 方法引发第二个异常

...您的进程不会立即终止。但是,您会丢失信息,因为 .NET 毫不客气地将第一个异常替换为第二个异常。因此,调用堆栈上方某处的 catch 块将永远不会看到第一个异常。然而,人们通常对第一个例外更感兴趣,因为这通常会提供更好的线索来说明事情开始出错的原因。

由于 .NET 缺乏一种机制来检测是否在异常挂起时正在执行代码,因此 IDisposable 的实现方式似乎只有两种选择:

  • 始终吞下 Dispose() 中发生的所有异常。不好,因为您最终可能还会吞下 OutOfMemoryException、ExecutionEngineException 等,我通常宁愿在它们发生时让进程终止,而没有另一个异常已经挂起。
  • 让所有异常从 Dispose() 传播出去。不好,因为您可能会丢失有关问题根本原因的信息,请参见上文。

那么,两害相权取其轻?有没有更好的办法?

编辑:澄清一下,我不是在谈论是否主动从 Dispose() 抛出异常,我是在谈论让 Dispose() 调用的方法抛出的异常传播到 Dispose() 之外,例如:

0 投票
8 回答
35193 浏览

c# - 在 .NET 中重写 Dispose(bool disposing) 有什么意义?

如果我在 C# 中编写一个实现 IDisposable 的类,为什么不足以让我简单地实现

处理释放任何非托管资源?

总是必要的,有时是必要的,还是完全不同的东西?

0 投票
4 回答
4050 浏览

c# - 识别 IDisposable 对象

我必须查看其他人编写的代码,该代码有一些内存泄漏。现在我正在搜索一次性对象以使用 using 语句将它们包含在内,我想知道是否有一种快速方法可以告诉您声明的所有一次性对象。我的意思是像 resharper 或其他 Visual Studio 插件。

谢谢。

0 投票
5 回答
3918 浏览

c# - IDisposable GC.SuppressFinalize(this) 位置

我为我的代码使用默认的 IDisposable 实现模板(模式)。

片段:

我的问题:为什么在 Dispose 公共方法中调用“GC.SuppressFinalize(this)”?在处置托管资源后,我会将“GC.SuppressFinalize(this)”放在受保护方法的“if (isDisposing)”部分中。

像这样:

0 投票
4 回答
1212 浏览

c# - C# 析构函数(又名:终结器)所涉及的成本?

析构函数应该只释放你的对象持有的非托管资源,它不应该引用其他对象。如果您只有托管引用,则不需要(也不应该)实现析构函数。您只希望它用于处理非托管资源。因为有一个析构函数需要一些成本,所以你应该只在消耗有价值的、非托管资源的方法上实现它。

-- C++ 程序员的 C# 十大陷阱

本文没有对此进行更深入的讨论,但是在 C# 中使用析构函数会涉及哪些成本?

注意:我知道 GC 和析构函数在可靠时间没有被调用的事实,除此之外,还有什么其他的吗?

0 投票
6 回答
9270 浏览

c# - IDisposable 有什么用途?

如果 .NET 有垃圾收集,那么为什么必须显式调用IDisposable

0 投票
3 回答
2993 浏览

.net - 跟踪未处理的一次性对象

是否有一种工具可以扫描您的代码并确定哪些实现 IDisposable 的对象在编译时或运行时没有被释放到代码库中?

我在代码中有可能没有处理对象的区域,但是很难回头看看哪些对象首先需要这样做。