请问,有人可以解释一下,在这段代码中会出现什么异常?
function CreateBibleNames: TStrings;
begin
Result := TStringList.Create;
try
Result.Add('Adam');
Result.Add('Eva');
Result.Add('Kain');
Result.Add('Abel');
except
Result.Free;
raise;
end;
end;
Run Code Online (Sandbox Code Playgroud)
因为我使用delphi,所以我曾经使用过一次异常处理.我认为上面的代码是由熟练的程序员编写的,我不认为异常是多余的.但是,在这个概念中使用异常处理对我来说仍然是一个谜.它似乎是一个安全的代码(没有尝试除了结束).我已经多次看到类似这样的代码片段,这就是为什么尽管有我的经验,这可能是一个很好的理由以这种方式编写,但这并不是必要的.
此外,当事情失败时,我会得到异常描述......
感谢名单
Nic*_*ges 12
好吧,那段代码很奇怪,我同意,而且我完全理解为什么它这样编写.但它是这样编写的,因为代码背后的前提是错误的.构造看起来很奇怪的事实应该是"代码味道",并且应该告诉你可能没有尽可能以最好的方式完成某些事情.
首先,这就是为什么try ...中的异常构造除了块.该函数创建一个TStringList,但如果在填充过程中出现问题,那么创建的TStringList将在堆上"丢失"并将成为内存泄漏.因此,原始程序员是防御性的,并确保如果发生异常,将释放TStringList,然后再次引发异常.
现在这里是"坏前提"部分.该函数返回一个TStrings实例.这并不总是最好的方法.返回像这样的对象的实例会引出一个问题"谁将要处理我创建的这个东西?".它创建了一种情况,在调用方面可能很容易忘记已经分配了TStrings实例.
这里的"更好的实践"是让函数将TStrings作为参数,然后填写现有实例.这样,毫无疑问谁拥有该实例(调用者),从而管理其生命周期.
因此,该函数成为一个过程,可能如下所示:
procedure CreateBibleNames(aStrings: TStrings);
begin
if aStrings <> nil then
begin
aStrings .Add('Adam');
aStrings .Add('Eva');
aStrings .Add('Kain');
aStrings .Add('Abel');
end;
end;
Run Code Online (Sandbox Code Playgroud)
现在这并不是说每次返回一个对象实例都是一件坏事 - 例如,这是非常有用的Factory模式的唯一功能.但是对于像这样的更"一般"的功能,上面是一种"更好"的做事方式.
从函数返回新构造的对象时,这是一个很好的习惯.在比字符串列表更复杂的场景中,某些不变量可能会被破坏或发生其他错误,因此会出现异常,在这种情况下,您希望释放返回值.在可能发生这种情况时,不必检查每种可能的情况,通常一个好的做法是使用单一模式返回新构造的对象并随处跟随它.
这样,当您构建的对象的实现在将来发生变化时,如果它们碰巧抛出异常,您仍然是安全的.
我会这样编写代码,原因如下:
1)通过标准化内存分配的外观,可以轻松检查源代码以查看是否缺少某些内容,而无需读取所有行。在这里,您只看到 .Create,并注意到异常处理很好,因此您不必阅读 try... except 之间的部分。
2)通过标准化内存分配的编码方式,即使在必要时,您也永远不会忘记这样做。
3)如果您稍后更改源代码、插入一些代码、更改 .Add 的工作方式、用其他内容替换 TStringList 等,那么它不会破坏此代码。
4)这意味着你不必考虑TStringList.Add()是否会抛出异常,从而解放你的大脑去从事其他提供更多价值的工作。
归档时间: |
|
查看次数: |
747 次 |
最近记录: |