为什么我不应该总是在C#中使用可空类型

时间:2009-05-06 16:50:47

标签: c# null c#-2.0 nullable

自从这个概念在.net 2.0中引入以来,我一直在寻找一些很好的指导。

为什么我要在c#中使用不可为空的数据类型? (一个更好的问题是为什么我不能默认选择可空类型,只有在明确有意义时才使用非可空类型。)

在其非可空对等体上选择可空数据类型是否会产生“重大”性能影响?

我更喜欢将我的值检查为null而不是Guid.empty,string.empty,DateTime.MinValue,< = 0等,并且通常使用可空类型。而且我不经常选择可空类型的唯一原因是我脑后的痒感让我感觉它不仅仅是向后兼容性而是强迫额外的'?'明确允许空值的字符。

是否有人总是(最常见)选择可空类型而不是非可空类型?

感谢您的时间,

7 个答案:

答案 0 :(得分:46)

您不应该总是使用可空类型的原因是,有时您可以保证将 值初始化。你应该尝试设计你的代码,以便尽可能经常这样。如果一个值无法被初始化,那么就没有理由认为null应该是一个合法的值。作为一个非常简单的例子,考虑一下:

List<int> list = new List<int>()
int c = list.Count;

总是有效。没有可能的方式c未被初始化。如果它变成int?,你实际上会告诉读者代码“这个值可能为null。确保在使用它之前检查”。但我们知道这种情况永远不会发生,为什么不在代码中公开这种保证?

在值是可选的情况下,您绝对正确。如果我们有一个可能会或可能不会返回字符串的函数,则返回null。不要返回string.Empty()。不要回归“魔法价值”。

但并非所有值都是可选的。并且使一切都是可选的使得代码的其余部分变得更加复杂(它增加了另一个必须处理的代码路径)。

如果您可以特别保证此值始终有效,那么为什么要丢弃这些信息呢?这就是你通过使它成为可以为空的类型所做的。现在值可能存在,也可能不存在,使用该值的任何人都必须处理这两种情况。但是你知道,首先只有其中一种情况可能发生。您的代码用户也应该受到青睐,并在您的代码中反映这一事实。然后,您的代码的任何用户都可以依赖有效的值,他们只需要处理一个案例而不是两个案例。

答案 1 :(得分:9)

因为总是必须检查可空类型是否为null是不方便的。

显然有些情况下,值是真正可选的,在这种情况下,使用可空类型而不是幻数等是有意义的,但在可能的情况下,我会尽量避免它们。

// nice and simple, this will always work
int a = myInt;

// compiler won't let you do this
int b = myNullableInt;

// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;    

// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();

答案 2 :(得分:3)

我认为语言设计者认为'默认情况下可以为空的引用类型'是一个错误,而且非可空是唯一合理的默认值,您应该选择进入nullness。 (这就是许多现代函数式语言中的情况。)“null”通常是一堆麻烦。

答案 3 :(得分:3)

您似乎有两个不同的问题......

  

为什么我要在C#中使用不可为空的数据类型?

很简单,因为编译器保证您所依赖的值类型数据实际上具有值!

  

为什么我不会默认选择可空类型,只有在明确有意义时才使用非可空类型?

正如Joel已经提到的,如果类型是引用类型,则它只能为null。编译器保证值类型具有值。如果您的程序依赖于变量来获取值,那么这就是您不希望选择可空类型所需的行为。

当然,当您的数据来自不是您的计划的任何地方时,所有投注都会被取消。最好的例子来自数据库。数据库字段可以是null,因此您希望程序变量模仿此值 - 而不仅仅是创建“魔术”值(即-1,0或其他)“代表”null。您可以使用可空类型执行此操作。

答案 4 :(得分:1)

尽管null值可以方便地用作“not-initialized-yet”或“not-specified”值,但它们会使代码更复杂,主要是因为你重载了 {{1}的含义} 以及变量(number-or-null与just-a-number)。

许多数据库设计人员和SQL数据库程序员都喜欢使用NULL值,但是对于问题的思考可以稍微改变一下,你可以消除空值,实际上代码更简单,更可靠(例如,不用担心{{1} } S)。

实际上对“T”的需求很大。使任何引用类型不可为空的运算符,类似于“T?”使价值类型成为可空,而C#的发明者Anders Hejlsberg希望他能够将这种能力纳入其中。

另见问题Why is “null” present in C# and java?

答案 5 :(得分:0)

我倾向于在任何有意义的地方使用Nullable类型 - 在问题出现之前我不会关心性能,然后我会修复它所在的几个区域并完成它。

但是,我也发现,一般来说,我的大多数值最终都是不可为空的。事实上,有很多次我真的喜欢NotNullable,我可以使用引用类型来查找null时遇到null问题,而不是稍后当我尝试使用它时。

答案 6 :(得分:-1)

唯一应该使用Nullable Type的情况是,数据库表中的某个字段绝对要求应用程序在某个时刻发送或接收null。即使在这种情况下,也应该总是试图找到使用Nullable类型的方法。布尔并不总是你最好的朋友。