不可为空的类型

时间:2009-04-05 09:20:21

标签: c#

有没有办法在C#中创建一个不可为空的类型(比如DateTime或TimeSpan)。?

还有一种方法(可能是一个属性)强制在不添加

的情况下不会将null参数传递给方法和属性
if(arg1 == null)
{
   throw new ArgumentNullException("this attribute is null")
}

9 个答案:

答案 0 :(得分:16)

DateTimeTimeSpan不可为空,因为它们是struct而不是class es。

至于你的第二个问题,在C#中没有标准的方法可以做到这一点。您可以使用PostSharp(一个AOP框架)或Spec#来实现这一点,这是一种全新的语言(C#的扩展),它允许一些期望的行为。

答案 1 :(得分:11)

您在.NET 4.0 / C#4.0中通过代码契约更容易引用的空值检查,这几乎可以满足您的需求。

结构已经不可为空了​​,但是不要像疯了一样创建你自己的结构 - 你很少需要它们(类更常见)。没有“非可空类”的真正概念;人们有提出的语法更改,如:

void Foo(string! arg1) {...}

这将使编译器对arg1进行非空检查 - 但实际上,代码合同会做到这一点以及更多。在PostSharp中你可以做一些事情,但它可能不值得使用。

另一个关于非可空类的想法(以及未实现的原因之一);对于一个不可为空的类,default(T)会是什么? ;-p规范要求 default(T)定义明确......

答案 2 :(得分:6)

非可空类型是ValueType,换句话说是结构。结构不能为null,因此示例如下:

public struct MyStruct {}

没有内置的方法可以确保null不作为参数传递给方法(除非参数的类型是ValueType)。我已经看到人们创建扩展方法来做一个关于参数是否为null的更简单(即更少的代码)断言,这可能是一个选项。另一方面,检查很短;并且检查的意图非常清楚。如果您使用自定义检查方法,情况可能并非如此。

C#4.0将通过合同为这种编程添加更好的选项,但目前尚不可用。正如另一个答案所指出的那样PostSharp是做你想做的事情的选择。 PostSharp的工作原理是添加一个后编译步骤,其中添加了额外的代码。

但是,有一些选项可以静态检查是否可以传递null。例如,ReSharper允许您使用[NotNull]属性装饰自己的方法参数,如果ReSharper可以确定参数可能为null,则它将在编译时发出警告。当然,这只会警告您(可能)不良的编码实践,它不是运行时检查,不应该这样使用。

答案 3 :(得分:4)

你是对的:与C ++相比,这是C#的一个缺点。这是一种耻辱,因为我传递给函数的所有参数的95%都是非空指针。在C ++中,您可以添加编译器检查的文档,指出哪些指针可以指向某些内容。

答案 4 :(得分:2)

除了提到的AOP解决方案之外,Enterprise Library还在其验证块中提供了此功能。 http://msdn.microsoft.com/en-us/library/ff953182(v=pandp.50).aspx

答案 5 :(得分:1)

Structs(值类型)变量永远不会为null - 这解释了您的DateTime案例。因此,如果你的方法params是C#结构,你可以确定它们永远不会为null 但是,如果您的方法参数是引用类型,则它们可以为null。我不认为你可以取消上面在这种情况下显示的空检查。

答案 6 :(得分:1)

关于第二个问题,这是一个受Nullable<T>启发的想法。

带有空检查参数的方法如下所示:

void Foo(NotNull<string> s)
{
    var x = $"{s}";
    var i = int.Parse(s);
}

NotNull<T>的使用不仅限于方法参数。如果该语言将来有一些语法上的优势,例如Foo(string! s)

public struct NotNull<T> where T : class
{
    private T valueField;

    public NotNull(T value)
    {
        this.valueField = value;
        this.CheckNotNull(value);
    }

    public T Value => this.valueField;

    public static implicit operator T(NotNull<T> t)
    {
        return t.Value;
    }

    public static implicit operator NotNull<T>(T t)
    {
        return new NotNull<T>(t);
    }

    public override bool Equals(object other)
    {
        return this.Value.Equals(other);
    }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode();
    }

    public override string ToString()
    {
        return this.Value.ToString();
    }

    private void CheckNotNull(T value)
    {
        if (value == null)
        {
            throw new InvalidOperationException($"Value cannot be null");
        }
    }
}

答案 7 :(得分:0)

当然,您可以编写自己的值类型(enumstruct),这些值不能为null(除非可以为空)。

至于第二部分,你可以有一个泛型参数和一个只接受值类型的约束,这意味着参数不能为null - 考虑到我们使用class的绝大多数情况,这不是很有用。

public static void Do<T>(T arg1) where T : struct
{
    //both struct and enum goes here.
}

答案 8 :(得分:0)

根据Anders Hejlsberg在Microsoft Build 2019中的讲话,C#8.0将具有不可为空的类型。 https://mybuild.techcommunity.microsoft.com/sessions/77385?source=sessions