自动处置延期方式合理吗?
我一直在编写一些自定义 WinForm 控件,这些控件执行大量绘图,因此往往有大量基于一次性图形的字段(画笔、笔、位图等),因此我的控件的 Dispose()方法必须对每个方法调用 Dispose。
我担心我(或未来的维护者)很容易错过需要处理的字段,要么忘记处理它,要么没有意识到它实现了 IDisposable。因此,我在 Object 上编写了一个非常简单的扩展方法,它查找所有 IDisposable 字段并处理它们:
static public void DisposeAll(this Object obj)
{
var disposable = obj.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.Select(fi => fi.GetValue(obj))
.Where(o => o != null && o is IDisposable)
.Cast<IDisposable>();
foreach (var d in disposable) d.Dispose();
}
我的问题基本上是这是否合理。我想不出它可能会搞砸什么,但是我对 WinForms 的内部工作原理并不是特别熟悉,这似乎是一种可能会导致令人恼火的错误的事情(扰乱反射和处理)。
I've been writing some custom WinForm controls which do a pretty heavy amount of drawing and therefore tend to have a lot of disposable graphics based fields lying around (Brushes, Pens, Bitmaps etc..) and as a result my Control's Dispose() method has to call Dispose on each of them.
I got concerned that I (or a future maintainer) could easily miss a field that needs to be disposed, either by forgetting to Dispose it or by not realising that it implements IDisposable. As such I wrote a very simple extension method on Object which finds all the IDisposable fields and disposes of them:
static public void DisposeAll(this Object obj)
{
var disposable = obj.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.Select(fi => fi.GetValue(obj))
.Where(o => o != null && o is IDisposable)
.Cast<IDisposable>();
foreach (var d in disposable) d.Dispose();
}
My question is basically whether this is a reasonable thing to do. I can't think what it might screw up, but then I'm not particularly familiar with the inner workings of WinForms and this seems like the kind of thing (messing with reflection and disposing) that might cause irritating bugs down the line.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
通常您不想处置所有一次性成员。例如对父表单的引用。
Usually you don't want to dispose all disposable members. E.g. a reference to the parent form.
不,这不是一个好方法。您在 OnPaint 方法中创建的绘图对象应始终是局部变量,并由 using 语句包装。您的方法需要声明一个类,只是为了存储这些对象。痛苦且低效。此外,您还将处置不应该处置的对象。就像预制笔和画笔一样,例如 Pens.Black。
No, this is not a good approach. The drawing objects you create in an OnPaint method should always be local variables, wrapped by a using statement. Your approach requires declaring a class, just to store those objects. Painful and inefficient. Furthermore, you'll dispose objects that should never be disposed. Like the prefab pens and brushes, Pens.Black for example.
很难说它是否适合您的特定情况;我发现最大的问题是
Dispose()
调用的顺序。如果一个非托管句柄依赖于另一个句柄,那么您将在绘图、内存等方面遇到奇怪的问题。恕我直言。
It's tough to say if it will work for your particular case; I see greatest problem in order of
Dispose()
invocations. If one unmanaged handle depends on another you will have a weird problem with drawing, memory etc.IMHO.
我认为这很危险。如果你实现这个想法,那么该对象将被处置(如果它是一次性的),并且在某些情况下,例如当你需要该对象存在时,它将会消失。
自动化对于您确信它们根本不会被引用的对象有好处。
I think this is dangerous. If you implement this idea, then the object will be disposed (if its disposable), and in certain situations like when you need the object to be present, it will be gone.
Automation is good for the objects which you are sure of that they will not be referred back at all.
您可以使用 FxCop 或 代码分析(Visual Studio 2010 Premium 或更高版本)。
规则 CA2213 将查找您忘记处理的字段。
You can use FxCop or Code Analysis (Visual Studio 2010 Premium or better).
Rule CA2213 will look for fields that you forgot to dispose.