有没有办法在C#中创建一个不可为空的类型(比如DateTime或TimeSpan)。?
还有一种方法(可能是一个属性)强制在不添加
的情况下不会将null参数传递给方法和属性if(arg1 == null)
{
throw new ArgumentNullException("this attribute is null")
}
答案 0 :(得分:16)
DateTime
和TimeSpan
不可为空,因为它们是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)
当然,您可以编写自己的值类型(enum
和struct
),这些值不能为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