【问题标题】:Nicer way of parameter checking?更好的参数检查方式?
【发布时间】:2011-03-24 16:52:33
【问题描述】:

我们使用 .NET 2.0 框架和 C# 3.0(我认为这是可以在 2.0 版本框架上运行的 C# 的最后一个版本,如果我错了,请纠正我)。

C# 中是否有内置的东西可以使这种类型的参数验证更方便?

public ConnectionSettings(string url, string username, string password,
                          bool checkPermissions)
{
    if (username == null) {
        throw new ArgumentNullException("username");
    }

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

    if (String.IsNullOrEmpty(url)) {
        throw new ArgumentException("Must not be null or empty, it was " +
            (url == null ? url : "empty"), "url");
    }

    this.url = url;
    this.username = username;
    this.password = password;
    this.checkPermissions = checkPermissions;
}

这种参数验证成为一种常见模式,并导致在我们的公共方法中涉及大量“几乎是样板”的代码。

如果没有内置任何东西。有什么很棒的免费库可供我们使用吗?

【问题讨论】:

  • 我认为需要更改此行以避免空引用异常? (url == null ? url : "空"), "url"); to (url == null ? "null" : "empty"), "url");
  • 您正在寻找面向方面的编程工具。我知道有一些可以与 Visual Studio 集成,并在编译时将代码注入您的程序集 IL。但今天早上我的谷歌似乎无法正常工作。
  • 你应该能够敲出一些方便的方法来提供大部分功能,但我同意,为此最好有一些合成糖。我特别讨厌为 string.IsNullOrEmpty 的两种情况抛出两个单独的异常
  • 不要满足于任何让您将参数名称放在字符串中的东西。它最终会与真实姓名不同步,而使用 lambda 表达式可以自动确定正确的姓名。

标签: c# parameters parameter-passing


【解决方案1】:

我通常创建静态辅助方法...

例如

public static void CheckNotNull(object value, string parameterName)
{
   if(value == null) { throw new ArgumentNullException(parameterName); }
}

意味着您可以将代码压缩成类似于下面的内容,并使其更整洁。

CheckNotNull(username, "username");
CheckNotNull(password, "password"); 

或者你可以把它包装成一个扩展方法:

public static void CheckNotNull<T>(this T value, string parameterName)
{
   if(value == null) { throw new ArgumentNullException(parameterName); }
}

并像这样使用:

username.CheckNotNull("username");
password.CheckNotNull("password");

如果您觉得很花哨,您可能可以使用反射来询问参数名称。反射有点慢,所以只有在要抛出异常时才这样做,但它可以节省你一直输入文字参数名称的时间。

【讨论】:

  • 仍然需要将参数名称放在一个字符串中(您已经方便地省略了)。
  • Ben,这确实是一个错误,但在否决之前已修复。
  • 谢谢本。我还添加了关于反射的评论,我不知道如何从头顶上实现它,但如果它是可行的并解决整个讨厌的字符串问题,应该提供一个简洁的解决方案。
  • 你不能,用那个语法。你需要一个表达式树。例如stackoverflow.com/questions/1608714/…
  • 糟糕,我的剪贴板上的 URL 错误。我的意思是链接charlieflowers.wordpress.com/2009/04/01/…
【解决方案2】:

您可以使用像 Post Sharp 这样的 il weaver,请记住,C# 5 中的编译器即服务会内置这种东西。

我个人不推荐这种方法,除非问题很大并且必须解决。通常,如上所述的一些断言和检查先决条件是最佳实践。

EG:

public ConnectionSettings(
   [NotNullOrEmpty] string url, 
   [NotNull] string username, 
   [NotNull] string password,
   bool checkPermissions)
{
    this.url = url;
    this.username = username;
    this.password = password;
    this.checkPermissions = checkPermissions;
}

您还可以将此类东西与code contracts 集成,这将允许您执行一些丰富的静态分析。

【讨论】:

    【解决方案3】:

    Here's a nice fluent way 这样做。

    What are your favorite extension methods for C#? (codeplex.com/extensionoverflow)

    public static class Extensions
    {
            public static void ThrowIfArgumentIsNull<T>(this T obj, string parameterName) where T : class
            {
                    if (obj == null) throw new ArgumentNullException(parameterName + " not allowed to be null");
            }
    }
    
    internal class Test
    {
            public Test(string input1)
            {
                    input1.ThrowIfArgumentIsNull("input1");
            }
    }
    

    【讨论】:

    • Giorgi 已经提到过这种方法。另外......你仍然有那个丑陋的字符串,里面有参数名称。
    【解决方案4】:

    您可以使用合同来做到这一点,但这是相同的概念。

    无论如何,这应该是一个很好的做法,因为它清楚地显示了公共方法上的必填字段。

    【讨论】:

      【解决方案5】:

      它没有内置在 .Net Framework 中,但您可以使用 Fluent Argument Validation

      【讨论】:

        【解决方案6】:

        类似于 Giorgi 提到的 fluent 参数验证的想法,但是这个想法避免了参数的冗余命名,以及代码重构工具无法自动更新的字符串。

        http://charlieflowers.wordpress.com/tag/parameter-validation/

        【讨论】:

          【解决方案7】:

          只是添加到上面 Sam 的回答中,这里有一个链接,它告诉您如何使用 PostSharp 实现这些属性:

          http://dpatrickcaldwell.blogspot.com/2009/03/validate-parameters-using-attributes.html

          【讨论】:

            【解决方案8】:

            我最近发布了Guard 的第一个稳定版本,这是一个可以帮助您编写如下保护子句的库:

            public ConnectionSettings(
                Uri url, string username, string password, bool checkPermissions)
            {
                this.username = Guard.Argument(() => username).NotNull();
                this.password = Guard.Argument(() => password).NotNull();
                this.url = Guard.Argument(() => url).NotNull().Https();
                this.checkPermissions = checkPermissions;
            }
            
            • 它比您想象的要快,this document 深入研究了性能注意事项。
            • 您可以通过扩展方法的形式添加新的验证,this document 详细解释。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-06-01
              • 1970-01-01
              • 2011-02-07
              相关资源
              最近更新 更多