验证公共/私有方法的函数参数时的最佳实践

时间:2013-06-06 18:14:06

标签: c# validation

做一些研究,似乎人们普遍认为公共方法的论据应该得到验证,而私人职能通常不会。这让我有些疑问,但到目前为止我还没有找到满意的答案。

示例:

public void DoSomething(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

思想:

  1. 如果i内的DoWork()要求为非负变化怎么办?设计风险留下过时的验证检查。我知道,程序员负责调整已更改的函数的使用情况,但这让我想知道是否有更好的方法可以将错误风险降至最低。

  2. 对来自DoWork()的{​​{1}}的不同来电怎么样?我们必须冗余地验证这些论点吗?

  3. DoSomething()

    通过将支票放入自己的功能中,可以稍微清理一下。然后,调用public void DoSomething(int i) { if (i < 0) throw new ArgumentOutOfRangeException("i"); double d = DoWork(i); } public void DoSomethingElse() { int i = 5; if (i < 0) throw new ArgumentOutOfRangeException("i"); double d = DoWork(i); } private double DoWork(int i) { double ret = ...; // some calculation return ret; } 的新功能可能会忘记验证DoWork(int i)

    i

    这一点比这更好吗?

    public void DoSomething(int i)
    {
        ThrowIfIntegerIsNegative(i);
    
        double d = DoWork(i);
    }
    
    public void DoSomethingElse()
    {
        int i = 5;
        ThrowIfIntegerIsNegative(i);
    
        double d = DoWork(i);
    }
    
    static void ThrowIfIntegerIsNegative(int i)
    {
        if (i < 0)
            throw new ArgumentOutOfRangeException("i");
    }
    
    private double DoWork(int i)
    {
        double ret = ...; // some calculation
        return ret;
    }
    

    根据具体情况,这些是我想要同时实现的目标:

    1. 在一个地方(可能在使用参数的函数内)进行参数验证
    2. 尽快报告错误(可能不想让一堆代码运行一小时,最后因为一些糟糕的用户输入而失败)
    3. 避免多次验证参数
    4. 避免在发布代码中影响性能
    5. 你如何取得平衡?哪种方法最适合您?我非常感谢任何见解。

3 个答案:

答案 0 :(得分:9)

在公共方法中验证参数而不在私有方法中验证参数的逻辑大致如下:

  
      
  • 使用无效参数调用公共方法时,控件之外的编程错误。
  •   
  • 使用无效参数调用非公共方法时,控件中存在逻辑错误。
  •   

这个逻辑是合理的:没有必要浪费周期来验证模块内部生成的方法的参数。另一方面,私有方法总是可以假设它们的参数是有效的,因为你可以控制所有私有方法的调用。

然而,在违反这些假设的情况下捕捉情况是非常有益的。为此,在私有方法中使用运行时断言代替参数验证是一个非常好的主意。这会从外部调用者捕获带有异常的无效调用,并通过断言警告您使用自己的方法进行无效调用。

答案 1 :(得分:1)

我喜欢在公共方法中验证异常:

public void Foo(int i)
{
    if (i < 0)
      throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

我喜欢用私有方法验证Asserts:

private double DoWork(int i)
{
    System.Diagnostics.Debug.Assert(i >= 0);
    // ....
}
  1. 这意味着在多个公共方法中进行重复验证。
  2. 尽早捕获无效参数。
  3. 由于参数名称的不同等原因,私有方法中的参数无效而引发ArgumentOutOfRangeException异常可能会使公共方法的调用者感到困惑。
  4. 通常,您的公共方法在调用私有方法之前会执行其他工作,以便保存工作。
  5. 使用单元测试确保新方法不会错过任何验证检查。
  6. 要做的另一件事是将任何受保护的方法视为公共方法。

    修改

    这是一个错误验证的例子,违反了上面的#3:

    public void Foo(int distanceInMetres)
    {
        double d = DoWork(distanceInMetres * 1000);
    }
    
    private double DoWork(int distanceInMillimetres)
    {
        if (distanceInMillimetres < 0)
          throw new ArgumentOutOfRangeException("distanceInMillimetres");
        // ....
    }
    

    如果Foo的来电者在参数“distanceInMillimetres”上看到异常,他会感到困惑,因为他打电话给“Foo”,后者拿了一个名为“distanceInMetres”的参数。

答案 2 :(得分:1)

同意有关公共方法而非公开方法的dasblinkenlight声明。

如果您练习TDD,那么您的私有方法只是重构代码并将一些公共方法提取到私有方法中的结果。因此,如果您使用测试覆盖公共方法,则会自动测试您的私有方法。

如果您不使用TDD但想要验证逻辑是否未被违反,您可以使用不同的技术,例如 - 断言(http://msdn.microsoft.com/en-us/library/ttcc4x86.aspx)或代码合同(http://msdn.microsoft.com/en-us/library/dd264808.aspx)。