设置 IDisposable 属性时调用 Dispose?
我今天更改了 FxCop 规则,将任何未处理的 IDisposables 指出为错误,希望它可以帮助我追踪一些 GDI 泄漏。有趣的是,它向我指出了一个我不太确定如何处理的例子:
public class CustomGoRectangle : GoRectangle
{
public void DoStuff()
{
Pen p = new Pen(Color.Red, 4.0f);
this.Pen = p;
}
public void DoOtherStuff()
{
Pen p = new Pen(Color.Blue, 4.0f);
this.Pen = p;
}
public void Test()
{
this.Pen = Pens.Green;
DoStuff();
DoOtherStuff();
}
}
快速解释。 GoRectangle 位于第 3 方库中,并具有 Pen 属性,它不是 IDisposable。
我把笔放在了很多地方,就像上面的例子一样。这里说明的问题是,调用 DoStuff()
我创建了一支新笔,它从未被释放。现在,如果在分配新值之前 this.Pen 不为 null,我可以调用 dispose,但正如 Test()
所示,如果已设置系统笔,这只会导致进一步的问题。处理这种情况的实际模式是什么?
I switched the FxCop rule today to point out any non-disposed IDisposables as errors, in a hope that it might help me track down some GDI leaks. Interestingly it pointed me to an instance that I'm not quite sure how to deal with:
public class CustomGoRectangle : GoRectangle
{
public void DoStuff()
{
Pen p = new Pen(Color.Red, 4.0f);
this.Pen = p;
}
public void DoOtherStuff()
{
Pen p = new Pen(Color.Blue, 4.0f);
this.Pen = p;
}
public void Test()
{
this.Pen = Pens.Green;
DoStuff();
DoOtherStuff();
}
}
Quick explanation. GoRectangle is within a 3rd party library and has a Pen property, it isn't IDisposable.
I set my pen in a number of places, like the contrived example above. The problem illustrated here is that calling DoStuff()
I create a new pen, which is never disposed. Now I could call dispose on this.Pen if it's not null before assigning a new value, but then as Test()
illustrates if a System Pen has been set this will just cause further problems. What's the actual pattern for dealing with situations like this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以在重新分配之前手动调用
this.Pen.Dispose()
。You could manually call
this.Pen.Dispose()
before reassigning it.不,您不能处置所有笔,因为如果您尝试处置它们,系统笔将抛出
ArgumentException
(我刚刚使用反射器进行了检查)。但是,您可以使用反射来获取 Pen 中私有字段
immutable
的值。如果为false
,您可以安全地处理笔。 (我不知道单声道是否以同样的方式工作)这里有一个扩展方法可以帮助您:
在分配新笔之前调用它。
No, you can't dispose all pens since system pens will throw
ArgumentException
if you try to dispose them (I just checked using reflector).However, you can use reflection to get the value of the private field
immutable
in the Pen. If it'sfalse
you can safely dispose the pen. (I do not know if mono works in the same way)Here is an extension method to help you:
Call it before assigning a new pen.
我通常处理此类事情的方式如下:
1)向图书馆提供者投诉。
2) 创建一个处置包装类,允许控制在处置包装器时是否实际处置其包装实例。例如(忽略 Dispose(bool) 噪音):
3) 使用处置包装器来允许及早清理已知允许处置的实例。例如:
不幸的是,这意味着通过 Pen 属性分配的 Pen 实例在完成之前不会被清理。如果您担心这一点,您可能需要考虑扩展处置包装器,以检测是否可以通过反射读取其不可变字段的值来清理 Pen,如 jgauffin 的答案所述。
Here's the way I usually handle this sort of thing:
1) Complain to the library provider.
2) Create a disposition wrapper class that allows one to control whether its wrapped instance will actually be disposed when the wrapper is disposed. e.g. (ignoring Dispose(bool) noise):
3) Use the disposition wrapper to allow early clean-up of instances for which disposition is known to be permissable. e.g.:
Unfortunately, this means that Pen instances assigned via the Pen property won't be cleaned up until they are finalized. If you are concerned about this, you might want to consider extending the disposition wrapper to detect whether the Pen can be cleaned up by reading the value of its immutable field via reflection, as mentioned jgauffin's answer.
对于需要 IDisposable 对象来使用另一个对象的情况,理想的方法是使用一个参数来指示被赋予 IDisposable 对象引用的对象是否应该拥有该对象的所有权。坚持获取传入的 IDisposable 所有权的对象(例如 StreamReader)可能与从不接受所有权的对象一样烦人。鉴于 GoRectangle 不接受所有权,因此无论谁创建与 GoRectangle 一起使用的笔,都将负责处置它。假设应处置任何非不可变画笔的方法是危险的,因为无法保证被放弃的 GoRectangle 使用的任何画笔不会被仍在范围内的其他对象共享。
The ideal approach for the situation where an IDisposable object is needed to use another object is to have a parameter which indicates whether an object which is given a reference to an IDisposable object should take ownership of it. An object which insists upon taking ownership of a passed-in IDisposable (e.g. StreamReader) can be as annoying as one which never accepts ownership. Given that GoRectangle does not accept ownership, whoever creates a pen for use with a GoRectangle will be responsible for disposing it. Approaches which assume any non-immutable pen should be disposed are dangerous, because there's no guarantee that any pen that's used by a GoRectangle that's being abandoned won't be shared by some other object that's still in scope.
任何 Disposable 对象都应该在不需要时手动处理,而不是依赖 GC。
在您的情况下,您可以采用 2 种策略:
Any Disposable object it should be disposed manually when no need it, and not relaying on GC.
In your case you can adopt 2 strategies: