我正在制作一个RAII类,它接受一个System.Windows.Form控件,并设置它的光标.在析构函数中,它将光标设置回原来的状态.
但这是个坏主意吗?当这个类的对象超出范围时,我可以安全地依赖析构函数吗?
Jon*_*eet 20
这是一个非常非常糟糕的主意.
当变量超出范围时,不会调用终结器.它们在对象被垃圾收集之前的某个时刻被调用,这可能是很长一段时间之后.
相反,你想实现IDisposable,然后调用者可以使用:
using (YourClass yc = new YourClass())
{
// Use yc in here
}
Run Code Online (Sandbox Code Playgroud)
那将Dispose自动调用.
在C#中很少需要终结器 - 只有在您直接拥有非托管资源(例如Windows句柄)时才需要它们.否则,您通常会有一些托管包装类(例如FileStream),如果需要,它将具有终结器.
请注意,您只需要任何的这个时候,你必须要清理资源-大多数类在.NET 不落实IDisposable.
编辑:只是约嵌套评论作出回应,我同意它可以是一个有点难看,但你不应该需要using陈述非常经常在我的经验.你可以像这样垂直嵌套使用,如果你有两个直接相邻的:
using (TextReader reader = File.OpenText("file1.txt"))
using (TextWriter writer = File.CreateText("file2.txt"))
{
...
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 12
你知道,很多聪明的人说"如果你想在C#中实现RAII,就使用IDisposable",而我只是不买它.我知道我在这里是少数,但是当我看到"使用(blah){foo(blah);}"时,我自动认为"blah包含一个非托管资源,需要在foo完成后立即进行清理(或投掷)以便其他人可以使用该资源".我不认为"blah不包含任何有趣的内容,但是需要发生一些语义上重要的突变,我们将通过字符'}'表示语义上重要的操作" - 某些突变就像某些堆栈必须弹出或某些标志必须重置或其他.
我说如果你有一个语义上重要的操作,必须在某些事情完成时完成,我们有一个单词,那个单词是"finally".如果操作很重要,那么它应该表示为一个语句,你可以在那里看到并设置一个断点,而不是一个右大括号的隐形副作用.
那么让我们考虑一下你的特定操作.你想代表:
var oldPosition = form.CursorPosition;
form.CursorPosition = newPosition;
blah;
blah;
blah;
form.CursorPosition = oldPosition;
Run Code Online (Sandbox Code Playgroud)
那段代码非常清楚.所有副作用都在那里,对于想要了解代码正在做什么的维护程序员来说是可见的.
现在你有一个决策点.怎么回事呢?如果blah抛出然后发生意外的事情.你现在不知道"形式"是什么状态; 它可能是"形式"中的代码.它可能是一些突变的中途,现在处于一些完全疯狂的状态.
鉴于这种情况,你想做什么?
1)将问题提交给其他人.没做什么.希望调用堆栈中的其他人知道如何处理这种情况.表格已经处于不良状态的原因; 光标不在正确位置的事实是它最不担心的事实.不要盯着已经如此脆弱的东西,据报道曾经有过例外.
2)将光标重置在finally块中,然后将问题报告给其他人.希望 - 没有任何证据证明你的希望将会实现 - 将光标重置在你知道处于脆弱状态的表单上本身不会引发异常.因为,那种情况会发生什么?可能有人知道如何处理的原始异常丢失了.您已经破坏了有关问题原始原因的信息,这些信息可能是有用的.而且你已经用一些关于光标移动故障的其他信息取而代之,这对任何人都没用.
3)编写处理(2)问题的复杂逻辑 - 捕获异常,然后尝试在单独的try-catch-finally块中重置光标位置,该块抑制新异常并重新抛出原始异常.这可能很难做到,但你可以做到.
坦率地说,我的信念是,正确答案几乎总是(1).如果出现了可怕的问题,那么你无法安全地推断脆弱国家的进一步突变是合法的.如果您不知道如何处理异常,那么放弃.
(2)是带有使用块的RAII给你的解决方案.同样,我们首先使用块的原因是在不再使用块时积极清理重要资源.无论是否发生异常,都需要快速清理这些资源,这就是"使用"块具有"最终"语义的原因.但"最终"语义不一定适用于非资源清理操作的操作; 正如我们所看到的,程序语义 - 负载最终阻止隐含地假设清理总是安全的; 但我们处于异常处理状态的事实表明它可能不安全.
(3)听起来很多工作.
所以总之,我说停止尝试这么聪明.你想改变光标,做一些工作,并取消突变光标.所以写完三行代码就完成了.没有华丽的裤子RAII是必要的; 它只是增加了不必要的间接性,它使得阅读程序变得更加困难,并且它使得它在特殊情况下可能更脆,而不是更脆弱.
编辑:显然,Eric和我对这种用法存在分歧.:○
你可以使用这样的东西:
public sealed class CursorApplier : IDisposable
{
private Control _control;
private Cursor _previous;
public CursorApplier(Control control, Cursor cursor)
{
_control = control;
_previous = _control.Cursor;
ApplyCursor(cursor);
}
public void Dispose()
{
ApplyCursor(_previous);
}
private void ApplyCursor(Cursor cursor)
{
if (_control.Disposing || _control.IsDisposed)
return;
if (_control.InvokeRequired)
_control.Invoke(new MethodInvoker(() => _control.Cursor = cursor));
else
_control.Cursor = cursor;
}
}
// then...
using (new CursorApplier(control, Cursors.WaitCursor))
{
// some work here
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1898 次 |
| 最近记录: |