使用try / finally try / except而不是begin / end被认为是一种不好的做法或存在任何缺点?

时间:2012-01-31 02:42:11

标签: delphi try-finally try-except

在我维护的某些应用中的许多地方,我发现代码在try/finallytry/except句中使用for loopif块,以避免使用开始/结束

考虑下一个代码(不是生产代码,只是一个样本)

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Classes,
  SysUtils;

Procedure TestNoBeginEnd;
var
 i   : Integer;
 L1  : TStringList;
begin
    for i := 1 to 10 do
    try
      L1:=TStringList.Create;
      try
        L1.Add('Bar');
        L1.Add(IntToStr(i));
        L1.Add('Foo');
      finally
        Writeln(L1.Text);
        L1.Free;
      end;
    except
      on E: Exception do
        Writeln('Opps '+E.ClassName, ': ', E.Message);
    end;
end;

begin
  try
    TestNoBeginEnd;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

问题,使用try / finally或try / except而不是delphi中的begin / end,被认为是一种不好的做法,代码嗅觉或存在任何缺点?

更新

我很抱歉愚蠢的示例代码,只是为了澄清try / finally并尝试/除了不假装替换开始/结束,只是为了避免使用它(开始/结束)当存在一个案例当使用try / finally或try / except时不需要开始/结束。

4 个答案:

答案 0 :(得分:6)

我个人认为不需要在begin..end附近添加额外的try..finally/except..end,尤其是在try之前或之后添加代码的可能性很小的情况下。 end

话虽如此,问题更多的是我们是否需要在begin..end..do之后系统地..then,即使只有一条指令(在您的情况下是{ {1}}指令)。

这主要是关于风格和习惯的问题,有些人更倾向于采取防御性编码和系统性地编写一个开头......其他人尽量避免使用不必要的线条。

当涉及到相当多的行时,我倾向于添加try..以使范围更明显。

我会说,使用良好的判断力,看看有人(或你)以后修改代码的可能性会超出预期的范围。

答案 1 :(得分:1)

首先要做的事情。开始/结束与Try / Etc不同。后者首先表示一组指令,而第二个是单个指令(其中可能包含大量指令)。

  

所以它们就像一把锤子和梯子。不同的工具   jobs.Ture你用梯子开钉子,但它不是最多的   处理问题的有效方法。

编辑: 如果我提出问题(现在你已编辑它),你会问是否可以尝试使用/ etc开始/结束。是的,你可以这样做,因为try / etc是一个单一的声明。事实上,我甚至可以说避免使用太多代码可能是一件好事。

编辑前:

那是什么意思?嗯,这意味着如果在该函数中发生错误,它将被记录,但基本上被忽略。

除非有非常好的异常处理并且代码会升级异常或正确恢复我会说这是不好的做法

在你的示例中,所有异常处理程序都是Opps(oops?)。这有什么用?当然它可能只是一个样本,因此我会检查代码,看看它到底做了什么。我相信写这篇文章的人一般都试图处理错误,但实际上使用这种模式会使代码的可靠性更差。

我使用'异常处理程序的一般情况是针对特殊情况的,我可以恢复,或者我需要让某人知道。大多数情况下,我发现没有人能够处理错误,系统必须按照设计降级。这是异常处理程序将安全记录并传递异常的地方。

后一种情况我延伸到系统中的所有“大边界”。即我将在服务/ API边界收集异常并适当地记录/包装。

(注意有时不好的API会在非特殊情况下使用异常,在这种情况下,您可以安全地添加异常处理程序来包装错误的设计。)

答案 2 :(得分:1)

您对问题的修改从根本上改变了问题。你应该至少改变了标题,现在我想知道问题是否可以挽救(-1)。

那说,在解决你的原始问题时:

当Begin / End语句足够时,不应使用Try / Finally或Try / Except语句。除了Try-statements为编译代码添加(微小甚至无法察觉)额外指令这一事实外,它们还意味着代码必需品不存在:

for I := 0 to Count - 1 do
try
  Inc(Rect.Left, Shift);
finally
  Inc(Rect.Right, Shift);
end;

不要这样做。

答案 3 :(得分:0)

当尝试finally /除了在块中包含相同的代码时,省略begin end没有任何问题。请记住,try-blocks比开始块有更多的开销。这个开销通常可以忽略不计,但我发现它在循环中产生了有意义的差异,特别是在重复引用的方法中循环。

考虑到上面的细节,你的例子有点差,因为它在循环中反复添加了不必要的开销。每当你可以将try块移出循环时,这是一件好事。在您的示例中,如果您必须能够捕获每个循环迭代的异常,则下面的代码将更有效,否则,也会移除except块。

Procedure TestNoBeginEnd;
var
 i   : Integer;
 L1  : TStringList;
begin
  L1:=TStringList.Create;
  try
    for i := 1 to 10 do
    try
      L1.Clear;
      L1.Add('Bar');
      L1.Add(IntToStr(i));
      L1.Add('Foo');
      Writeln(L1.Text);
      end;
    except
      on E: Exception do
        Writeln('Opps '+E.ClassName, ': ', E.Message);
    end;
  finally
    L1.Free;
  end;
end;