默认字符串初始化:NULL还是为空?[关闭]


130

我一直将字符串初始化为NULL,以为NULL表示缺少值,而“”或String.Empty是有效值。我最近看到了更多示例代码,其中String.Empty被视为默认值或不代表任何值。这让我感到奇怪,在c#中新添加的可为null的类型似乎使我们通过不使用NULL来表示“无值”来向字符串迈进。

您将什么用作默认的初始值设定项?为什么?

编辑:根据答案,我进一步思考

  1. 避免错误处理如果该值不应该为null,为什么NULL首先将其设置为?也许最好在错误发生的地方识别错误,而不是将错误掩盖在整个代码库中?

  2. 避免空检查如果您厌倦了在代码中进行空检查,那么抽象空检查是否更好?也许包装(或扩展!)字符串方法以使其NULL安全?如果您经常使用String.Empty并且null出现在系统中会NULL怎样,您是否仍会开始添加检查呢?

我不禁要回到懒惰的观点。如果您使用''而不是null在他的数据库中,那么任何DBA都会给您九种愚蠢的拍击方式。我认为相同的原则也适用于编程,应该有人来鼓吹那些使用String.Empty而不是NULL不代表任何价值的头脑。

相关问题


“桑尼”?一定不是我认识的达娜。
vfilby

@Joel,令我惊讶的是,有多少人对Zim或GIR一无所知。我也对我的一些朋友感到反感感到惊讶。并不是说这纯粹是善良,而是其中蕴含着令人敬畏的幽默。
vfilby

我知道,但有时候假装有趣。
Dana the Sane

1
我在MVC表单集合或会话变量上遇到了很多这个问题,我发现最有用的是用??将null转换为String.Empty。速记,然后应用所需的任何字符串操作。例如。(项目?? String.Empty).Trim()。ToUpper()
sonjz 2013年

4
这不是建设性的吗?
nawfal

Answers:


111

+1用于区分“空”和NULL。我同意“空”应表示“有效,但为空白”,而“ NULL”应表示“无效”。

所以我会这样回答你的问题:

当我想要一个可能会或可能不会更改的有效默认值(例如,用户的中间名)时为

如果后续代码未显式设置该值,则为NULL


11
当实际上在两者之间存在区别时,区分NULL和空是很好的。但是,在很多情况下,两者之间没有区别,因此用两种方式表示同一件事是一种责任。
格雷格·斯马尔特

6
@格雷格:虽然我同意多样性有可能引起混乱,但它也可能是一笔巨大的财富。编写“”或NULL以区分有效值和无效值的简单一致的约定将使您的代码更易于理解。这就是为什么我总是使用“ if(var)”来测试布尔值,使用“ if(var!= NULL)”来测试指针以及使用“ if(var!= 0)”来测试整数的原因-它们对编译器都意味着相同的含义,但它们包含其他信息,可以帮助维护我的代码的可怜开发人员。
亚当·利斯

32

根据MSDN

通过使用Empty值而不是初始化字符串null,可以减少NullReferenceException发生的机会。

但是,始终使用IsNullOrEmpty()是一种很好的做法。


45
仅仅因为您减少了例外的机会,并不意味着该例外不会发生。如果您的代码依赖于那里的值,它应该引发异常!
rmeador

1
当然,那里没有争论。OTOH,如果您只是将字符串附加在一起……我认为这取决于编码风格,经验和情况。
Tomalak

这主要是我使用的方法也要区分使用。
PositiveGuy2010年

3
不要忘记用于.NET Framework 4+的IsNullOrWhiteSpace()
Coops 2013年

13

您为什么要完全初始化字符串?在声明一个变量时,不必初始化变量,而在IMO中,仅应在代码块的上下文中指定的值有效时才进行初始化。

我看到很多:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else
{
  name = "bar";
}

return name;

不初始化为null会同样有效。此外,大多数情况下,您希望分配一个值。通过初始化为null,您可能会错过未分配值的代码路径。像这样:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else if (othercondition)
{
  name = "bar";
}

return name; //returns null when condition and othercondition are false

当您不初始化为null时,编译器将生成一个错误,指出并非所有代码路径都分配一个值。当然,这是一个非常简单的示例...

马蒂斯


我相信几乎所有C#程序员都使用Visual Studio,您的第二种情况(不带= null)将生成警告,正是由于您所说的原因-字符串的默认值是否为null都无关紧要。如果您不能保证每个代码路径都可以分配,IDE(和/或我想底层的编译器[?])将生成警告。虽然警告不会妨碍编译,他们还在那里-让那些正在迎刃而解可以帮助混淆他人可保证程序员的关注
码赛马

据我所知,第一种情况下将不初始化非常高兴namenull(没有警告),因为每一个代码路径值赋给name-根本不需要初始化有
代码赛马

8

对于大多数实际上不是字符串处理软件的软件,程序逻辑不应依赖于字符串变量的内容。每当我在程序中看到以下内容时:

if (s == "value")

我感觉很不好 为什么此方法中有字符串文字?设置s什么?是否知道逻辑取决于字符串的值?是否知道必须使用小写字母才能工作?我应该通过更改使用来解决此问题String.Compare吗?我应该创建一个Enum并对其进行解析吗?

从这个角度来看,人们会想到一种非常简单的代码哲学:避免在任何可能的地方检查字符串的内容。比较字符串String.Empty实际上只是将其与文字进行比较的一种特殊情况:除非确实需要,否则避免这样做。

知道这一点,当我在代码库中看到类似以下内容时,我不会眨眼:

string msg = Validate(item);
if (msg != null)
{
   DisplayErrorMessage(msg);
   return;
}

我知道那Validate将永远不会返回String.Empty,因为我们编写的代码比那更好。

当然,世界其他地方并非如此。当您的程序处理用户输入,数据库,文件等时,您必须考虑其他原则。在那里,将代码强加给混乱是代码的工作。该顺序的一部分是知道什么时候应该为空字符串String.Empty,什么时候应该为空null

(只是为了确保我没有说话,我只是在我们的代码库中搜索了“ String.IsNullOrEmpty”。它的所有54次出现都在处理用户输入,从Python脚本返回值,检查从中检索到的值的方法中。外部API等)


6

这实际上是C#语言中的一个巨大漏洞。无法定义不能为空的字符串。这就引起了与您所描述的问题一样简单的问题,这迫使程序员做出他们不必做的决定,因为在许多情况下,NULL和String.Empty表示同一件事。反过来,这又可能迫使其他程序员不得不同时处理NULL和String.Empty,这很烦人。

一个更大的问题是数据库允许您定义映射到C#字符串的字段,但是可以将数据库字段定义为NOT NULL。因此,无法使用C#类型在SQL Server中准确表示一个varchar(100)NOT NULL字段。

其他语言(例如规范#)也允许这样做。

在我看来,C#无法定义不允许为null的字符串与以前无法定义允许为null的int一样严重。

完全回答您的问题:我总是使用空字符串进行默认初始化,因为它与数据库数据类型的工作方式更加相似。(编辑:此语句非常不清楚。它应显示为“当NULL为多余状态时,我使用空字符串进行默认初始化,与在将NULL为多余状态时将数据库列设置为NOT NULL的方式相同。 ,我的许多DB列都设置为NOT NULL,因此,当我将它们带入C#字符串时,该字符串将为空或具有值,但永远不会为NULL。换句话说,我仅将字符串初始化为NULL如果null的含义不同于String.Empty的含义,并且我发现这种情况不常见(但是这里的人给出了这种情况的合法示例)。”)


使用的String.Empty只是类似于一个的一个数据库字符串被定义的方式。使用null表示没有值与使用null nvarchar更加一致。我认为,如果您使用“代表无价值”,那么任何值得付出代价的DBA都会给您打九种愚蠢的方法。
vfilby

格雷格(Greg)实际上,您的做法是错误的。非空值类型最不能“说明数据库类型如何工作”,因为它们永远无法容纳null,因此也无法映射到可为空的列。根据合同,任何字符串都可以映射到任何varchar列。
Tor Haugen

您是对的,我的最后主张还不够明确。大多数时候,我的数据库列不是NOT NULL(因为空字符串和NULL的含义之间没有区别),所以我尝试通过从不在其中存储null来保持字符串相似,这就是我的意思。
格雷格·斯马尔特

5

这取决于。

您是否需要知道该值是否丢失(是否有可能未定义)?

空字符串是使用该字符串的有效值吗?

如果您对两者的回答均为“是”,则需要使用null。否则,您将无法分辨“无值”和“空字符串”之间的区别。

如果您不需要知道是否没有值,那么空字符串可能会更安全,因为它使您可以在任何使用过的地方跳过空检查。



3

我将其设置为“”或为null-我始终使用String.IsNullOrEmpty进行检查,所以也可以。

但是内心的极客说我应该在将其设置为适当的值之前将其设置为null ...



2

这可能是一种避免错误的技术(建议还是不建议)。由于“”仍然是字符串,因此您可以在其上调用字符串函数,如果它为NULL,则将导致异常?


1
那就是我通常听到的借口,听起来像是懒惰。“在我看来,我不想打扰检查此值,所以我会走捷径”。
vfilby

是的,我不同意。可能有一些情况下减少错误校验码是不错的量,但没有任何效果的函数调用是不是最大的要么..
达纳理智的

2

我总是将它们初始化为NULL

总是string.IsNullOrEmpty(someString)它来检查它的价值。

简单。


1

这取决于实际情况。在大多数情况下,我使用String.Empty,因为我不想每次尝试使用字符串时都进行null检查。它使代码简化了很多,并且您不太可能引入不必要的NullReferenceException崩溃。

仅在需要知道是否已设置字符串以及将字符串设置为有效的空字符串时,才将字符串设置为null。实际上,我发现这些情况很少见。


1

空字符串是一个值(顺便说一句,恰好不含任何字母的一段文本)。Null表示无值。

当我希望表明变量不指向或不包含实际值时(当意图是无值时),我将变量初始化为null。


1

重申Tomalak响应,请记住,当将字符串变量分配给初始值null时,您的变量不再是字符串对象。与C#中的任何对象相同。因此,如果您尝试访问变量的任何方法或属性,并且假定它是字符串对象,则将获得NullReferenceException异常。


1

仅在值是可选的情况下才应使用Null。如果该值不是可选的(例如“名称”或“地址”),则该值绝不能为null。这适用于数据库以及POCO和用户界面。Null表示“此值是可选的,当前不存在。”

如果您的字段不是可选的,则应将其初始化为空字符串。将其初始化为null会将您的对象置于无效状态(根据您自己的数据模型无效)。

就我个人而言,我希望字符串默认情况下不可为空,而仅当我们声明“ string?”时才可为空。尽管从更深层次上讲这可能不可行或合乎逻辑;不确定。



0

我认为没有理由不对未分配的值(或在程序流中此位置未发生的值)使用null。如果要区分,则== null。如果您只想检查某个值,而不管它是否为null或其他值,则String.Equals(“ XXX”,MyStringVar)很好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.