在某些情况下使用中止来改进/简化代码 [英] Using Abort to improve/simplify code in some situations

查看:217
本文介绍了在某些情况下使用中止来改进/简化代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前曾经讨论过: http://stackoverflow.com/a/42156860/937125
我不太明白为什么在这种情况下, Abort 比调用 Exit 更好。我倾向于不在我的代码流中使用它。我认为这是一个不好的做法,对代码流不利。
但@ David在评论中的发言让我想知道是否可能我缺少某些东西:

I had a discussion the other day: http://stackoverflow.com/a/42156860/937125 where I didn't quite understand why an Abort was better than calling Exit in that situation. I tend not to use it in my code flow. I consider it a bad practice and bad for code flow. but @David's statement in the comments made me wonder if maybe I was missing something:


没有一个无声的例外,怎么会当深度
在调用堆栈下时,您中止操作。例如,如何使用10个深层调用堆栈中止文件副本
操作?不是那个
异常是为什么设计的?确定你可以代码它没有例外
,但它是更冗长和容易出错。

Without a silent exception, how would you abort an operation when deep down the call stack. For instance how would you abort a file copy operation with a 10 deep call stack? Isn't that exactly what exceptions are designed for? Sure you can code it without exceptions but it is much more verbose and error prone.

我无法想象这样情况。有人可以给我一个这样的代码/场景的例子,并说服我在上述情况下 Abort 真的是一件好事,而且更容易出错。 (3-4深层调用堆栈足以说明)

I can't imagine such situation. Can someone give me an example of such code/scenario, and convince me that Abort in the above case is really a good thing and "much more verbose and error prone". (3-4 deep call stack is enough to illustrate)

推荐答案

说明我的观点的最简单的场景是这样的: p>

The simplest scenario that illustrates my point is like so:

procedure MethodA;
begin
  MethodB;
  MethodC;
end;    

procedure MethodB;
begin
  // ... do stuff
end;

procedure MethodC;
begin
  // ... do stuff
end;

很好,因为它是。现在假设 MethodB 询问用户的某些输入,如果用户按下取消按钮,则不再进行任何进一步的工作。你可以这样实现:

That's fine as it is. Now suppose that MethodB asks the user for some input, and if the user presses the Cancel button, that no further work should be carried out. You could implement that like this:

procedure MethodA;
begin
  if MethodB then
    MethodC;
end;    

function MethodB: Boolean;
begin
  Result := MessageDlg(...)=mrOK;
  if not Result then
    exit;
  // ... do stuff
end;

procedure MethodC;
begin
  // ... do stuff
end;

这样做很好,但是想像你在现实世界的代码中,有更深的嵌套。由 MethodB 返回的布尔值可能需要在很多级别上传递。这将变得麻烦。

That works fine, but imagine that you in the real world code, there was deeper nesting. The boolean returned by MethodB might need to be passed on up a great many levels. This would become cumbersome.

或者考虑如果 MethodB 需要向其调用者返回一个值,会发生什么。在这种情况下,原始代码可能是这样的:

Or consider what happens if MethodB needs to return a value to its caller. In that scenario the original code might be like so:

procedure MethodA;
begin
  MethodC(MethodB);
end;    

function MethodB: string;
begin
  Result := ...;
end;

procedure MethodC(Value: string);
begin
  // ... do stuff with Value
end;

现在再次考虑如果用户有机会取消会发生什么。如何从 MethodB 返回一个布尔值和一个字符串?对一个返回值使用out参数?使用复合结构(如记录)来包装这两个值。后者显然涉及到很多样板,所以我们来探讨一下这个原型。

Now once more consider what happens if the user gets a chance to cancel. How can we return both a boolean and a string from MethodB? Using an out parameter for one of the return values? Using a compound structure like a record to wrap both values. The latter obviously involves lots of boilerplate so let us explore the former.

procedure MethodA;
var
  Value: string;
begin
  if MethodB(Value) then
    MethodC(Value);
end;    

function MethodB(out Value: string): Boolean;
begin
  Result := MessageDlg(...)=mrOK;
  if not Result then
    exit;
  Value := ...;
end;

procedure MethodC(Value: string);
begin
  // ... do stuff with Value
end;

确定你可以做到这一点,但是这开始看起来像是异常的代码旨在简化。在这一点上,让我们考虑一个静态异常的存在, EAbort ,通过调用 Abort 引发不会导致顶级异常处理程序显示的消息。最后一点是沉默的意思。

For sure you can do this, but this is beginning to look like the sort of code that exceptions were designed to simplify. And at this point, let us consider the existence of a silent exception, EAbort, raised by calling Abort, that does not result in a message being shown by the top level exception handler. That last point is what is meant by silent.

现在代码变成:

procedure MethodA;
begin
  MethodC(MethodB);
end;    

function MethodB: string;
begin
  if MessageDlg(...)<>mrOK then
    Abort;
  Result := ...;
end;

procedure MethodC(Value: string);
begin
  // ... do stuff with Value
end;

优点是 MethodA 不需要担心取消。如果调用堆栈更深,顶部的 MethodA 之间的方法和 MethodB

The advantage is that MethodA does not need to worry about cancellation. And if the call stack was deeper, none of the methods between MethodA at the top, and MethodB at the point of user input, would need to know anything about cancellation.

另一个好处是, MethodB 可以保留其自然签名。它返回一个字符串。在发生故障的情况下,无论是从更传统的异常还是从用户取消,抛出异常。

A further benefit is that MethodB can retain its natural signature. It returns a string. In case of failure, either from a more traditional exception, or from user cancellation, an exception is thrown.

这个非常简单的例子比以前没有使用 Abort 的引用更为引人注目。但是,如果 MethodB 在调用堆栈中有4或5深,那么代码如何?

This very simple example isn't that much more compelling than the previous one that does not use Abort. But imagine what the code would look like if MethodB were 4 or 5 deep in the call stack?

我绝对不会说中止应该永远用于代替 exit 。我的信念是两者都有自己的位置。其中 Abort 是用户选择取消操作,而不希望在当前事件处理程序中进行更多处理。此外,由于用户明确地选择取消,不需要向他们呈现进一步的UI。您不需要一个消息框告诉用户他们已经取消了,他们已经知道了。

I am absolutely not saying that Abort should always be used in place of exit. My belief is that both have their place. Where Abort shines is when the user opts to cancel an operation and you don't want any more processing to take place in the current event handler. Furthermore, since the user expressly opted to cancel, no further UI needs to be presented to them. You don't need a message box telling the user that they cancelled, they already know that.

这篇关于在某些情况下使用中止来改进/简化代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆