【问题标题】:Refactoring Guard Clauses重构保护子句
【发布时间】:2010-12-08 13:06:56
【问题描述】:

人们采取哪些方法(如果有)来管理您班级中的guard clause 爆炸?例如:

public void SomeMethod<T>(string var1, IEnumerable<T> items, int count)
{
    if (string.IsNullOrEmpty(var1))
    {
        throw new ArgumentNullException("var1");
    }

    if (items == null)
    {
        throw new ArgumentNullException("items");
    }

    if (count < 1)
    {
        throw new ArgumentOutOfRangeException("count");
    }

    ... etc ....
}

在我目前正在处理的项目中,有许多类在公共方法上有一组类似的保护子句。

我知道 .NET 4.0 代码合同,但目前这不是我们团队的选择。

【问题讨论】:

    标签: c# validation guard-clause


    【解决方案1】:

    我见过的很多项目都使用静态 Guard 类。

    public static class Guard {
        public static void ArgumentIsNotNull(object value, string argument) {
            if (value == null)
                throw new ArgumentNullException(argument);
        }
    }
    

    在我看来,它使代码更简洁。

    Guard.ArgumentIsNotNull(arg1, "arg1");
    

    【讨论】:

    • 我刚刚发布了同样的内容。唯一的问题是它把这个方法放在堆栈跟踪的顶部,而不是把原始方法放在顶部,并不是说它有那么大。这种模式显然可以用于不同的类型来检查一系列值等......
    • 是的,这是我遇到的唯一问题。虽然很容易找到原来的调用方法。
    • 这与模拟代码契约的类本质上是一回事。
    • 刚刚用过这个。谢谢!第一行应该是“public static class Guard”而不是“public static Guard”
    • 我建议你用 [DebuggerHiddenAttribute] 注释保护方法。这样可以确保调试器不会在这些方法中停止,而是返回到原始方法。请参阅msdn.microsoft.com/en-us/library/… 如果您使用的是 ReSharper,您还可以使用 [ContractAnnotationAttribute] 注释保护方法,并且可以使用 [InvokerParameterName] 注释 argument 参数,从而为参数名称字符串提供智能感知。
    【解决方案2】:

    如果您不想走代码合同路线,简化它的一种方法是删除大括号:

    public void SomeMethod<T>(string var1, IEnumerable<T> items, int count)
    {
        if (string.IsNullOrEmpty(var1))
            throw new ArgumentNullException("var1");
    
        if (items == null)
            throw new ArgumentNullException("items");
    
        if (count < 1)
            throw new ArgumentOutOfRangeException("count");
    
        ... etc ....
    }
    

    除此之外,如果您反对 .Net 4.0 还不是黄金时间,还有一些方法可以模拟代码合同:

    http://geekswithblogs.net/Podwysocki/archive/2008/01/22/118770.aspx

    【讨论】:

    • 看在上帝的份上,不要这样做!不带大括号的 if 语句是给自己带来麻烦的好方法。
    • 当心这个! Apple 臭名昭著的goto fail 是不使用大括号的代价高昂的结果。 (完全披露:我有时不使用大括号,但前提是整个东西都放在一行上)
    • @RufusL:这发生在一种因没有像 C# 那样的安全网而臭名昭著的编程语言中。没有自尊的程序员会在 C# 程序中使用goto
    • 你指的是什么安全网?
    • @RufusL:你想知道多少?内存管理、范围保护、异常处理、IL 沙盒……我要继续吗?
    【解决方案3】:

    您可以考虑重构为Introduce a Null Object

    【讨论】:

      【解决方案4】:

      同时这里有一篇很棒的文章:http://haacked.com/archive/2013/01/05/mitigate-the-billion-dollar-mistake-with-aspects.aspx/

      我会考虑使用 NullGuard.Fody,因为我对 Fodys 减少样板代码的能力感到兴奋

      【讨论】:

        【解决方案5】:

        减少(不完全删除)保护子句数量的一种方法是了解它们存在的原因。很多时候,我们要防范对参数类型有效但对接受它们的方法无效的值。换句话说,方法是在由参数类型定义的域的子集上定义的。

        此类情况的解决方案是尝试定义一个子类型(例如,一个更严格的接口)并接受该类型作为参数。您可以在本文中找到一个说明性示例:Why do We Need Guard Clauses?

        当然,这种技术并不适用于所有情况。所有引用类型至少允许空引用。因此,我们的大多数方法都将在域的一部分上定义,而这又需要一个针对 null 的保护子句。

        但从积极的方面来说,这种技术有助于提高人们对接收比预期更普遍的参数的方法的认识。给该孔配管有助于改进总体设计。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-02-16
          • 2021-05-26
          • 1970-01-01
          • 1970-01-01
          • 2016-03-01
          • 1970-01-01
          • 2018-11-01
          相关资源
          最近更新 更多