关于c#:有没有办法要求提供给方法的参数不为null?

Is there a way to require that an argument provided to a method is not null?

有没有更好的方法要求方法中的参数不为空?我一直在检查我的方法需要的任何参数是否为空,如下所示。但我想知道是否有更好的方法。

1
2
3
4
5
6
7
public void MyMethod(string a, int b)
{
   if(a==null){throw new ArgumentNullException("a");}
   if(b==null){throw new ArgumentNullException("b");}

   //more stuff here
}


这是我认为C是从C++中倒退的几个领域之一。

在C++中,你可以写

1
void foo(Bar& bar) { /*...*/ }

为了向编译器和其他人清楚地表明,foo采用了Bar的实际实例。是的,有可能——通过努力——通过EDCOX1的0个引用空引用,但这不是真正合法的C++。

你在c中唯一的"解决办法"(类似的)是让你的classstruct,因为.net中的值类型不能是null(在你的例子中,b不能是null,因为它是System.Int32)。调用bar()不会编译:

1
2
3
4
5
6
7
8
9
10
11
    class A { }
    struct B { }

    static void foo(A a) { }
    static void bar(B b) { }

    static void Main(string[] args)
    {
        foo(null);
        bar(null);
    }

显然,C很好地使拥有null引用变得更加困难;例如,F没有可以为空的类型。

对于一些与此相关的有趣评论,请阅读空引用:十亿美元的错误(和评论)。

编辑:埃里克·利珀特在2013年2月的脚注中写道:"…当C第一次实现时,它总是具有可以为空的引用类型,…Nullable可以被实现用于任何类型,默认情况下,引用类型将不可为空。我们可以有一个类型系统,其中Nullable是表示"可以是null的字符串"的唯一合法方法。……"


我个人喜欢刀刃。条件。它很容易使用,并且使它更易于阅读。


没有别的更好的方法。这是许多微软图书馆处理这种情况的方式。

您总是可以使用扩展方法使其更加清晰。

1
2
3
4
5
static IsNullArgument(this Object o, string arg)
{
    if (o == null)
        throw ArgumentNullException(arg);
}

你可以写一些实用方法。这是爪哇的共同模式。

用户代码:

1
2
3
4
5
6
7
8
9
public void MyMethod(string a, int b)
{
    //validate each
    Objects.RequireNotNull(a);
    Objects.RequireNotNull(b);

    //or validate in single line as array
    Objects.RequireNotNullArray(a, b);
}

实施代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static class Objects
{
    public static T RequireNotNull<T>(T arg)
    {
        if(arg == null)
        {
            throw new ArgumentNullException();
        }
        return arg;
    }

    public static object[] RequireNotNullArray(params object[] args)
    {
        return RequireNotNullArray<object>(args);
    }

    public static T[] RequireNotNullArray<T>(params T[] args)
    {
        Objects.RequireNotNull(args);
        for(int i=0; i<args.Length; i++)
        {
            T arg = args[i];
            if(arg == null)
            {
                throw new ArgumentNullException($"null entry at position:{i}");
            }
        }
        return args;
    }

}

无法在异常中获取变量名。但是使用堆栈跟踪和源代码,应该可以轻松地跟踪。


Rick Brewster(paint.net的作者)在博客中介绍了一种流畅的API替代方案:

http://blog.getpaint.net/2008/12/06/a-fluent-approach-to-c-参数验证/