加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 在某些情况下使用Abort来改进/简化代码

发布时间:2020-12-15 09:40:59 所属栏目:大数据 来源:网络整理
导读:前几天我进行了讨论: https://stackoverflow.com/a/42156860/937125 在那里我不太明白为什么在这种情况下,Abort比调用Exit更好.我倾向于不在我的代码流中使用它.我认为这是一个不好的做法,对代码流程也不好. 但@David在评论中的陈述让我想知道我是否遗漏了
前几天我进行了讨论: https://stackoverflow.com/a/42156860/937125
在那里我不太明白为什么在这种情况下,Abort比调用Exit更好.我倾向于不在我的代码流中使用它.我认为这是一个不好的做法,对代码流程也不好.
但@David在评论中的陈述让我想知道我是否遗漏了一些东西:

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深度调用堆栈足以说明)

解决方法

说明我的观点的最简单方案是这样的:

procedure MethodA;
begin
  MethodB;
  MethodC;
end;    

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

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

这很好,因为它是.现在假设MethodB要求用户输入一些输入,如果用户按下取消按钮,则不应该执行进一步的工作.你可以像这样实现:

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返回的布尔值可能需要在很多级别上传递.这会变得很麻烦.

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

procedure MethodA;
begin
  MethodC(MethodB);
end;    

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

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

现在再一次考虑如果用户有机会取消会发生什么.我们如何从MethodB返回布尔值和字符串?使用out参数作为其中一个返回值?使用像记录这样的复合结构来包装两个值.后者显然涉及很多样板,所以让我们探索前者.

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;

您肯定可以这样做,但这开始看起来像是为了简化而设计的异常代码.在这一点上,让我们考虑一下通过调用Abort引发的静默异常EAbort的存在,它不会导致顶级异常处理程序显示消息.最后一点是沉默的含义.

现在代码变成:

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之间的方法都不需要了解有关取消的任何信息.

另一个好处是MethodB可以保留其自然特征.它返回一个字符串.如果发生故障,无论是来自更传统的异常,还是来自用户取消,都会引发异常.

这个非常简单的例子并不比之前不使用Abort的例子更引人注目.但想象一下,如果MethodB在调用堆栈中是4或5深,代码会是什么样子?

我绝对不是说Abort应该总是用来代替退出.我的信念是两者都有自己的位置. Abort闪耀的地方是当用户选择取消操作并且您不希望在当前事件处理程序中进行任何更多处理时.此外,由于用户明确选择取消,因此不需要向他们呈现进一步的UI.您不需要一个消息框告诉用户他们已取消,他们已经知道了.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读