109

是否有一个简单的属性或数据协定可以分配给阻止null在 C#/.NET 中传递的函数参数?理想情况下,这还将在编译时检查以确保文字null没有在任何地方用于它和在运行时 throw ArgumentNullException

目前我写的东西像......

if (null == arg)
  throw new ArgumentNullException("arg");

...对于我期望不会出现的每一个论点null

同样,是否存在与Nullable<>以下情况相反的情况:

NonNullable<string> s = null; // throw some kind of exception
4

6 回答 6

70

不幸的是,在编译时没有任何可用的东西。

我最近在我的博客上发布了一个hacky 解决方案,它使用了新的结构和转换。

在带有代码合同的 .NET 4.0 中,生活会好很多。拥有实际的语言语法和对不可为空性的支持仍然非常好,但代码合同将有很大帮助。

我在MiscUtil中还有一个名为 ThrowIfNull 的扩展方法,它使它更简单一些。

if (null == arg)最后一点 - 使用“ ”而不是“ ”的任何理由if (arg == null)?我发现后者更容易阅读,而前者在 C 中解决的问题不适用于 C#。

于 2008-11-14T20:49:25.480 回答
32

我知道我在这个问题上来得太晚了,但我觉得随着 C# 的最新主要迭代接近发布,然后发布,答案将变得相关。在 C# 8.0 中将发生重大变化,C# 将假定所有类型均不为空。

根据 Mads Torgersen 的说法:

问题是空引用非常有用。在 C# 中,它们是每个引用类型的默认值。默认值是什么?在您决定分配给它的其他值之前,变量还有什么其他值?在您开始填充之前,我们还可以用什么其他值来铺平一个新分配的引用数组?

此外,有时 null 本身就是一个合理的值。有时您想表示一个事实,例如,一个字段没有值。可以为参数传递“nothing”。不过,有时重点是。这就是问题的另一部分:像 C# 这样的语言不允许您在此处表达 null 是否是一个好主意。

因此,Mads 概述的解决方案是:

  1. 我们认为,希望引用不为空更为常见。可以为空的引用类型会比较少见(尽管我们没有好的数据可以告诉我们多少),所以它们应该需要一个新的注释。

  2. 该语言已经有了可空值类型的概念和语法。两者之间的类比将使语言添加在概念上更容易,并且在语言上更简单。

  3. 除非您已经主动决定想要它们,否则您不应该用繁琐的 null 值给自己或您的消费者带来负担,这似乎是正确的。Nulls,而不是没有它们,应该是您明确必须选择加入的东西。

所需功能的示例:

public class Person
{
     public string Name { get; set; } // Not Null
     public string? Address { get; set; } // May be Null
}

该预览版适用于 Visual Studio 2017、15.5.4+ 预览版。

于 2018-02-08T16:50:00.707 回答
18

我知道这是一个非常古老的问题,但这里缺少这个问题:

如果您使用 ReSharper/Rider,您可以使用Annotated Framework

编辑:我刚刚得到一个随机的-1这个答案。没关系。请注意它仍然有效,即使它不再是 C#8.0+ 项目的推荐方法(要了解原因,请参阅Greg 的回答)。

于 2013-03-07T21:48:38.383 回答
9

查看企业库中的验证器。您可以执行以下操作:

private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
    get {
        return _someVariable;
    }
    set {
        _someVariable = value;
    }
}

然后在您想要验证它的代码中:

Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();

ValidationResults vrInfo = InternalValidator.Validate(myObject);
于 2008-11-14T21:23:47.003 回答
0

不是最漂亮的,但是:

public static bool ContainsNullParameters(object[] methodParams)
{
     return (from o in methodParams where o == null).Count() > 0;
}

您也可以在 ContainsNullParameters 方法中获得更多创意:

public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
       {
            var nullParams = from o in methodParams
                             where o.Value == null
                             select o;

            bool paramsNull = nullParams.Count() > 0;


            if (paramsNull)
            {
                StringBuilder sb = new StringBuilder();
                foreach (var param in nullParams)
                    sb.Append(param.Key + " is null. ");

                containsNullParameters = new ArgumentNullException(sb.ToString());
            }
            else
                containsNullParameters = null;

            return paramsNull;
        }

当然你可以使用拦截器或反射,但这些很容易遵循/使用,开销很小

于 2011-04-05T12:50:58.440 回答
-3

好的,这个回复有点晚了,但这是我解决它的方法:

public static string Default(this string x)
{
    return x ?? "";
}

使用此扩展方法,您可以将 null 和空字符串视为同一事物。

例如

if (model.Day.Default() == "")
{
    //.. Do something to handle no Day ..
}

我知道不理想,因为您必须记住在任何地方都调用默认值,但这是一种解决方案。

于 2011-10-04T22:09:28.760 回答