使用一次性对象的类的层次结构。对所有这些都实施 IDisposable 吗?
我有一个使用文件流的类。当应用程序关闭时,它需要关闭流,因此我使该类实现 IDisposable。
该类是另一个类的成员,另一个类是另一个类的成员,等等。一直到我的主应用程序。
因此,我是否必须在这些类的所有上实现IDisposable?
如果我将来更改文件实现以便它在每次写入后关闭文件怎么办?我现在有一整套无缘无故实现 IDisposable 的类。
我想我对将 IDisposable 语义强行塞入类中感到不舒服,这些类除了链下的一些轻微的实现细节之外不需要它们。有什么办法可以解决这个问题吗?
I have a class that uses a filestream. It needs to close the stream when the app shuts down, so I make the class implement IDisposable.
That class is a member of another class, which is a member of another class etc. All the way up to my main app.
Do I therefore have to implement IDisposable on all of these classes?
What if I change my file implementation in the future so that it closes the file after each write? I now have a whole set of classes that implement IDisposable for no reason.
I guess I'm uncomfortable with crowbarring IDisposable semantics into classes that have no need for them other than some slight implementation detail way down the chain. Are there any ways around this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
根据经验,当类型在实例字段中保留对 IDisposable 的引用时,我也将其设置为一次性。但我通常会尽量避免让自己陷入这种境地;如果可能,我尝试使用创建一次性物品的相同方法,使用
using
块来处理一次性物品。As a rule of thumb, when a type keeps a reference to an
IDisposable
in an instance field, I make it disposable too. But I usually try to avoid finding myself in this situation; when possible, I try to dispose disposables in the same method where they were created, with ausing
block.一般来说,如果您的类型包含实现
IDisposable
的成员,则该类型也应该实现IDiposable
。这是强制执行IDisposable
模式的最简单方法。我使用的一个例外是,如果我的类型契约包含一个方法,该方法 1) 必须被调用,2) 发出
IDisposable
资源使用结束的信号。在这种情况下,我觉得不实现 IDisposable 而是使用该方法调用 Dispose 很舒服In general if your type contains a member that implements
IDisposable
the type should also implementIDiposable
as well. It's the easiest way to enforce theIDisposable
pattern.The one exception I use is if my types contract contains a method which 1) must be called and 2) signals the end of use for the
IDisposable
resource. In that case I feel comfortable not implementingIDisposable
and instead using that method to callDispose
如果您明确想要处置文件流,那么是的,您需要在任何持有 IDisposable 引用的类上实现 IDisposable。如果在每次写入后处理文件流是合理的,即不会因频繁写入而损害性能,这听起来更可取。
If you explicitly want to dispose the filestream, then yes, you need Implement IDisposable on any classes that hold a reference to your IDisposable. If it is reasonable to dispose the filestream after each write, i.e. does not hurt performance due to frequent wries, that sounds preferrable.
这取决于您如何实现使用文件流的类。如果该类创建了文件流,那么它应该负责处理它。但是,如果您要更改它,以便该方法接受文件流作为参数,它将不再“拥有”文件流,因此不负责处置它。
如果该类是某种层次结构的一部分,您只需从顶部开始添加一个文件流作为参数,然后将其引入到实际使用的所有方法中。
例如:
虽然我不确定自己是否会使用这种模式,但这将允许您不必将“IDisposable”添加到除最初创建 Filestream 对象的类之外的任何类中。
It depends on how you implement the class that uses the filestream. If that class creates the filestream, then it should be responsible for disposing of it. However, if you were to change it so the method took in a filestream as a parameter, it would no longer 'own' the filestream and therefore not be responsible for disposing of it.
If the class is part of some kind of hierarchy, you can just add a filestream as a parameter starting at the top and introduce it to all methods down to where it is actually used.
For example:
While I'm not sure I'd use this pattern myself, this will allow you to not have to add 'IDisposable' to any classes except for the one that originally created the Filestream object.
您需要在每个中实现
IDisposable
,但这并不一定需要在每个代码中显式实现。让继承为您完成工作。两种方法:
现在我们可以这样做:
等等。
这一切都有效,因为
TextHandlingClass
继承了它需要的唯一的IDisposable
实现。如果我们有进一步的处置需求,那就会变得很棘手:
假设我们有一个类来处理池化
XmlNameTable
对象(为什么这对于另一个线程来说是一个好主意)并处置它,将表返回到池中,并由XmlHandlingClass
使用。现在,我们可以在某种程度上处理这个问题:现在,这适用于:
但不适用于:
在后一种情况下,仅使用
FileHandlingClass
实现(幸运的是,没有将池名称表返回到池是小问题,大多数Dispose()
情况更为重要)。因此,如果需要重写,我们应该这样做:现在我们在调用
Dispose()
时更加安全,但仍然只需要在重要的地方自己实现它。在第二种情况下,性能受到了微小的影响,但这确实是微小的。我现在指出这一点只是为了反对在任何情况下都考虑第一个,因为在任何情况下都认为需要重写 Dispose() 甚至被认为是模糊合理的。
You need an implementation of
IDisposable
in each, but that doesn't necessarily require an explicit implementation in the code of each. Let inheritance do the work for you.Two approaches:
Now we can do:
etc.
This all works because
TextHandlingClass
inherits the only implementation ofIDisposable
it'll ever need.It gets tricker if we have further needs for disposing though:
Say we've a class that handles pooling
XmlNameTable
objects (why that's a good idea is for another thread) and disposing it returns the table to the pool, and it's used byXmlHandlingClass
. Now, we can deal with that to some extent with:Now, this works great with:
but not with:
In the latter case only the
FileHandlingClass
implementation is used (luckily not returning a pooled name-table to a pool is a minor matter, most cases ofDispose()
are much more crucial). Hence if needing overrides is possible, we should do:Now we have much more safety in the calls to
Dispose()
, but still only need to implement it ourselves where it matters.There's a minute performance hit in the second case, but it really is minute. I'm pointing it out now only to argue against considering the first in any case where needing to override
Dispose()
is seen as even vaguely plausible.在任何给定时刻,实现 IDisposable 的每种类型的每个实例都应该至少有一个(通常是恰好一个)实体,可以预期在不再需要该实体之后、在完全最终放弃该实体之前的某个时间对其调用 Dispose 。如果您的类型具有 IDisposable 类型的字段,但可以预期其他东西会处置它可能引用的任何 IDisposable 实例,那么您不应该自己对该字段调用 Dispose。如果您的类型具有 IDisposable 字段,一旦您使用完该对象,其他人就不会使用该对象,并且预计没有其他人会 Dispose 它,那么您应该在不再需要该对象时对该对象调用 Dispose。在许多情况下,您的对象将需要另一个对象,直到没有其他对象需要您的对象为止,而您的对象会发现这一点的方式是当其他人对其调用 Dispose 时(随后它将对其他对象调用 Dispose)。
有时有用的一种模式是让一个类公开一个 Dispose 事件,每当调用 Dispose 时都会引发该事件。例如,如果另一个对象为您的对象提供了对 IDisposable 的引用,而该对象暂时需要该引用,然后为您提供 IDisposable 的对象就可以使用它,那么这会很有用。当您的对象仍然需要它时,它无法处置该对象,并且您的对象不会处置它(因为您的对象不知道提供 IDisposable 的对象是否已完成)。但是,如果为您的类提供 IDisposable 的类挂钩到您的对象的 Dispose 处理程序,则事件处理程序可以注意到您的对象不再需要 IDisposable,并且立即 Dispose 它(如果您的对象是最后一个需要它的对象)或设置一个标志,以便当其他用户完成该对象时,它将被处理)。
如果您的对象将拥有一组在其整个生命周期中保留的一次性对象,则另一种有用的模式是保留 IDisposable 对象的列表,然后让您的 Dispose 方法迭代该列表并处理其中的内容。列表中的每个项目都应在其自己的 Try/Catch 块中进行 Dispose;如果发生异常,则抛出 CleanupFailureException(自定义类型),该异常将第一个或最后一个此类异常作为其 InnerException,并且还包含作为自定义属性发生的所有异常的列表。
At any given moment, every instance of every type which implements IDisposable should have at least one (and usually exactly one) entity which can be expected to call Dispose on it sometime after it is no longer needed, and before it is completely and ultimately abandoned. If your type has a field of type IDisposable, but something else can be expected to dispose of any IDisposable instance it might refer to, then you should not call Dispose on that field yourself. If your type has an IDisposable field, nobody else is going to use that object once you're done with it, and nobody else is expected to Dispose it, then you should call Dispose on the object once you no longer need it. In many cases, your object will need the other object until such time as no other object needs yours, and the way your object will find that out is when someone else calls Dispose on it (whereupon it will call Dispose on the other objects).
One pattern which can sometimes be useful is to have a class expose a Disposed event which gets raised whenever Dispose is called. This can be useful if, e.g., an another object gives your object a reference to IDisposable which it will need for awhile, and then the object that gave you the IDisposable gets done with it. It can't dispose the object while your object still needs it, and your object isn't going to dispose it (since your object won't know whether the object that supplied the IDisposable is done with it). If the class which gave your class the IDisposable hooks to your object's Disposed handler, however, the event handler can then note that your object no longer needs the IDisposable and either Dispose it immediately (if your object was the last one to need it) or set a flag so that when the other user is finished with the object it will get Disposed).
Another pattern which can be useful if your object will have a certain set of disposable objects that it will keep throughout its lifetime is to keep a List of IDisposable objects and then have your Dispose method iterate through the list and dispose things therein. Each item on the list should be Disposed within its own Try/Catch block; if an exception occurs, throw a CleanupFailureException (a custom type) which has either the first or last such exception as its InnerException, and also includes a list of all the exceptions that occurred as a custom property.