【问题标题】:How is validating a parameter "high up" on the callstack done?如何在调用堆栈上验证参数“high up”?
【发布时间】:2011-06-01 06:53:48
【问题描述】:

我一直在阅读《框架设计指南》一书,这是一本关于在 .NET 中设计框架的书,其中摘录了框架设计人员关于他们对每个部分(例如参数设计、异常处理等)做出的决定的摘录。

在参数设计下,其中一个技巧是尽可能“在调用堆栈上”验证参数。这是因为这里的工作并不像调用堆栈中的低端那样昂贵,因此在调用堆栈的高端进行验证时性能损失不会那么高。

这是否意味着当我将参数传递给方法或构造函数时,我会在执行任何其他操作之前验证它们,还是在使用参数之前这样做(因此定义中的参数之间可能有 100 行代码以及参数的用法)?

谢谢

【问题讨论】:

  • 我相信您的第一个结论是正确的,请在最后可能的情况下验证它,其中值可能会以一种会对性能产生不利影响或导致问题的方式进行更改。
  • 是的,你是对的,即首先验证然后执行代码(阅读按合同设计模式。)好处很简单。例外是昂贵的,尤其是当它们通过层冒泡时。所以先验证参数再执行代码是一种很好的做法。
  • 这是刚传入还是刚使用前?

标签: c# parameter-passing callstack


【解决方案1】:
  1. 倾向于在程序集的公共 API 中进行验证。这意味着公共类的公共方法。

  2. 更喜欢在类的公共方法中进行验证。因此,如果您的类需要指向另一个对象的非空指针才能正常工作,您可以通过要求它作为构造函数参数并在提供空指针时抛出异常来强制执行此操作。从那时起,任何成员方法都不需要测试指针是否为非空。

这个想法是没有用户可以通过提供无效数据来破坏您的类(或程序集)。当然,代码不会以任何一种方式工作,但如果您以受控方式失败,调用代码会更清楚地知道出了什么问题,并且您不会有诸如资源泄漏(或更糟)之类的令人不快的副作用。

【讨论】:

  • 附带说明,如果您是调用代码和被调用代码的作者,我认为尽早失败(允许抛出空 ptr 异常等)通常就足够了,而不是显式验证。无论哪种方式,都应该失败或尽早验证。
【解决方案2】:

快速失败通常是一种好习惯。传递给方法的所有参数都应尽快验证,之前不要执行任何不必要的计算,因为这样可以简化调试并更容易从错误情况中恢复。

关于输入验证,我认为性能是次要问题。

【讨论】:

    【解决方案3】:

    我没有阅读您提到的具体指南,但我希望他们谈论的是方法A 调用方法B 的情况,该方法调用方法C 并且参数值通过所有三个传递来电。最好在方法 A 的开头验证该参数,而不是在方法 C 中间的某个地方验证该参数,因为如果它无效,那么您可以跳过在 AB 中发生的所有内容以及C 的开始。如果在循环内调用 BC 则尤其如此,因为这样低级验证将发生多次,而不是在 A 的开头仅发生一次。

    当然,您必须平衡参数验证的复杂程度。如果您在使用它的同一个地方验证它可能会更容易理解。

    【讨论】:

      【解决方案4】:

      尽早在您的方法中验证它们!

      【讨论】:

        【解决方案5】:

        我认为这意味着您应该在收到数据后立即验证可能无效的数据。一旦它被验证,则不需要更多的检查。如果你等到调用堆栈的底部,那么你可能需要验证很多次,因为你的调用树可能有很多分支。

        我完全同意这个建议,但不是基于表现。通过在入口点进行验证,您可以更好地向提供数据的客户提供有意义的错误消息。通过减少您所做的验证量,您最终会得到更清晰的代码。

        【讨论】:

          猜你喜欢
          • 2023-03-04
          • 1970-01-01
          • 2013-03-07
          • 1970-01-01
          • 2018-05-09
          • 1970-01-01
          • 2014-08-30
          • 2014-03-09
          • 2017-11-09
          相关资源
          最近更新 更多