40

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

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

选择一个可以为空的数据类型而不是它的不可为空的对等体是否有“显着”的性能影响?

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

有没有人总是(最总是)选择可空类型而不是不可空类型?

谢谢你的时间,

4

7 回答 7

52

您不应该总是使用可空类型的原因是有时您能够保证一个值被初始化。而且您应该尝试设计您的代码,以便尽可能多地出现这种情况。如果一个值不可能被未初始化,那么 null 就没有理由成为它的合法值。作为一个非常简单的例子,考虑一下:

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

总是有效的。没有可能c未初始化的方法。如果它变成了int?,您实际上是在告诉代码的读者“此值可能为空。请务必在使用前检查”。但是我们知道这永远不会发生,那么为什么不在代码中公开这个保证呢?

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

但并非所有值都是可选的。并且使所有内容都是可选的,这会使您的其余代码变得更加复杂(它添加了另一个必须处理的代码路径)。

如果你可以明确保证这个值总是有效的,那为什么要扔掉这个信息呢?这就是您通过将其设为可为空的类型所做的。现在该值可能存在也可能不存在,任何使用该值的人都必须处理这两种情况。但你知道,一开始只有一种情况是可能的。因此,您的代码的用户可以帮个忙,并在您的代码中反映这一事实。然后,您的代码的任何用户都可以依赖该值是有效的,他们只需要处理一个案例而不是两个案例。

于 2009-05-06T17:15:59.177 回答
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();
于 2009-05-06T16:56:32.997 回答
3

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

于 2009-05-06T16:57:06.350 回答
3

你似乎有2个不同的问题......

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

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

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

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

当然,当您的数据来自不是您的程序的任何地方时,所有的赌注都没有了。最好的例子来自数据库。数据库字段可以是null,因此您希望您的程序变量模仿这个值 - 而不仅仅是创建一个“代表”的“神奇”值(即 -1、0 或其他)null。您可以使用可为空的类型来执行此操作。

于 2009-05-06T17:01:21.363 回答
1

尽管空值可以方便地用作“尚未初始化”或“未指定”值,但它们会使代码更加复杂,主要是因为您重载了null变量的含义(数字或null 与只是一个数字)。

NULL 值受到许多数据库设计人员和 SQL 数据库程序员的青睐,但是只要稍微改变一下对问题的思考,您就可以取消 null 值,并且实际上拥有更简单和更可靠的代码(例如,不用担心NullReferenceExceptions)。

实际上对“T!”的需求很大。使任何引用类型不可为空的运算符,类似于 "T?" 使值类型可以为空,C# 的发明者 Anders Hejlsberg 希望他能包含这种能力。

另请参阅问题,为什么 C# 和 java 中存在“null”?

于 2009-05-06T17:14:03.500 回答
0

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

但是,我也发现一般来说,我的大多数值最终都是不可为空的。事实上,很多时候我实际上都想要一个 NotNullable,当我得到 null 时,我可以使用它来找出 null 问题,而不是稍后尝试使用它时。

于 2009-05-06T16:56:47.787 回答
-2

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

于 2015-01-24T02:31:57.447 回答