Delphi 何时提出例外?

Delphi 何时提出例外?,delphi,Delphi,我认为这是一个最佳实践类别问题: 我有一个自定义控件-某种网格,可以容纳一些面板。其中一个面板是上次单击的当前活动面板 TMyGrid = class (TSomeKindOfGrid) published property CurrentPanel: TPanel read getCurPanel write setCurPanel; end; 我的问题是:如果在某个时刻有人请求CurrentPanel,而网格是空的,getCurPanel应该返回NIL还是引发异常 如果getC

我认为这是一个最佳实践类别问题:

我有一个自定义控件-某种网格,可以容纳一些面板。其中一个面板是上次单击的当前活动面板

TMyGrid = class (TSomeKindOfGrid)
  published
    property CurrentPanel: TPanel read getCurPanel write setCurPanel;
end;
我的问题是:如果在某个时刻有人请求CurrentPanel,而网格是空的,getCurPanel应该返回NIL还是引发异常

如果getCurPanel返回NIL,那么每次调用CurrentPanel时都必须检查NIL。还有一种可能是调用方忘记检查NIL。好吧,没有什么不好的事情会发生,因为它会尝试访问一个NIL对象。程序将很好地在那里崩溃。我得到了一个堆栈跟踪。 如果我在getCurPanel中引发异常,我只在一个地方进行检查是的,我很懒。 如果返回nil,则用户有机会检查返回值并跳过他或她打算对当前面板执行的任何操作:

panel := XYZ.currentPanel;
if Assigned(panel) and (panel.Index = 17) then
begin
上面的代码运行时没有任何不必要的中断

如果您立即引发异常,那么用户就没有机会发现是否存在当前面板。换言之,提出例外情况为时过早。与上面相同的代码将爆炸

但我承认这是我个人的偏好,可能是许多人的偏好,但不是所有人的偏好。这是一个意见问题

但是,您也可以公开PanelCount属性,而不是返回nil。如果人们有类似的东西要检查,如果计数为零,如果有人试图访问面板,您也可以提高。那么,现在时机还不成熟

正如您所看到的,有几种方法可以做到这一点

笔记 正如SilverWarrior在评论中正确地注意到的,currentPanel是一个已发布的属性,最终将出现在对象检查器中。它可以处理返回nil的属性,但不一定是引发异常的属性

因此:最好的建议是返回nil。

如果返回nil,则用户有机会检查返回值并跳过他或她打算对当前面板执行的任何操作:

panel := XYZ.currentPanel;
if Assigned(panel) and (panel.Index = 17) then
begin
上面的代码运行时没有任何不必要的中断

如果您立即引发异常,那么用户就没有机会发现是否存在当前面板。换言之,提出例外情况为时过早。与上面相同的代码将爆炸

但我承认这是我个人的偏好,可能是许多人的偏好,但不是所有人的偏好。这是一个意见问题

但是,您也可以公开PanelCount属性,而不是返回nil。如果人们有类似的东西要检查,如果计数为零,如果有人试图访问面板,您也可以提高。那么,现在时机还不成熟

正如您所看到的,有几种方法可以做到这一点

笔记 正如SilverWarrior在评论中正确地注意到的,currentPanel是一个已发布的属性,最终将出现在对象检查器中。它可以处理返回nil的属性,但不一定是引发异常的属性


所以:最好的建议是返回零。

没有区别。每次/每次访问不存在的面板时,都会出现异常,要么是您自己引发,要么是运行时引发。如果你想避免它,你必须先检查,不管是哪种情况。@SertacAkyuz不能保证访问nil指针会引发异常。这是未定义的行为。任何事情都有可能发生。可能会引发异常,或者您可能只是读取垃圾,或者您可能会丢弃内存,或者…或者。。。恶魔可能会从你的鼻子里飞出来@雷米尔博-嗨。你能对此发表评论吗?没有区别。每次/每次访问不存在的面板时,都会出现异常,要么是您自己引发,要么是运行时引发。如果你想避免它,你必须先检查,不管是哪种情况。@SertacAkyuz不能保证访问nil指针会引发异常。这是未定义的行为。任何事情都有可能发生。可能会引发异常,或者您可能只是读取垃圾,或者您可能会丢弃内存,或者…或者。。。恶魔可能会从你的鼻子里飞出来@雷米尔博-嗨。你能对此发表评论吗?我同意例外情况不是解决问题的办法,但例外情况不会让消费者有机会发现并对他们不是专家组做出反应,这是不正确的,至少不是一成不变的。这只会使它变得更加困难和不方便,需要一个try/except处理程序和一个新的、特定的异常类型,该异常类型专门标识没有当前面板,而其他异常类型理论上可以由同一try/except中包含的其他代码引发。丑陋、混乱和更复杂是在这种情况下避免异常的原因。当然,如果你抓住了异常,你也知道没有面板,这可能就是问题产生的原因。但这不是一个恰当的处理方法。OP在这种情况下不应该引发异常还有另一个原因。如果你检查代码O
P,前提是您可以看到声明的属性已发布。这意味着他很可能打算在设计期间在对象检查器中显示此属性。因此,虽然对象检查器被用来正确处理结果为retutn nil的属性,但我严重怀疑它是否能够处理任何引发的异常。事实上,通过在published属性中设置exception,您甚至可能会使对象检查器完全崩溃。@SilverWarior-Yes。CurrentPanel是一个已发布的属性,将在设计时使用。因此,您的答案是正确的。当然也可能有一个函数TryGetCurrentPanelout Panel:TPanel:boolean,它为调用者提供了一种在使用面板之前检查面板是否有效的简单方法。我同意例外情况不是解决方法,但这不是真的,或者至少不是一成不变的,一个例外让消费者没有机会去发现和反应他们不是面板。这只会使它变得更加困难和不方便,需要一个try/except处理程序和一个新的、特定的异常类型,该异常类型专门标识没有当前面板,而其他异常类型理论上可以由同一try/except中包含的其他代码引发。丑陋、混乱和更复杂是在这种情况下避免异常的原因。当然,如果你抓住了异常,你也知道没有面板,这可能就是问题产生的原因。但这不是一个恰当的处理方法。OP在这种情况下不应该引发异常还有另一个原因。如果您检查OP提供的代码,您可以看到声明的his属性已发布。这意味着他很可能打算在设计期间在对象检查器中显示此属性。因此,虽然对象检查器被用来正确处理结果为retutn nil的属性,但我严重怀疑它是否能够处理任何引发的异常。事实上,通过在published属性中设置exception,您甚至可能会使对象检查器完全崩溃。@SilverWarior-Yes。CurrentPanel是一个已发布的属性,将在设计时使用。因此,您的答案是正确的。当然,还可能有一个函数tryGetCurrentPanelOutPanel:TPanel:boolean,它为调用者提供了一种在使用面板之前检查面板是否有效的简单方法。