string.Empty和null,你会使用哪一个?

89

最近,我的一位同事告诉我不要使用 string.Empty 来设置字符串变量,而是使用 null,因为它会污染堆栈。

他说不要这样做:

string myString=string.Empty; 而是这样做:string mystring=null;

这真的有关系吗?我知道 string 是一个对象,所以这种做法有点合理。

我知道这是个愚蠢的问题,但你怎么看?


1
我不完全确定你为什么要这样做... 你能给出更多你所讨论的代码作为例子吗? - stusmith
我请我的同事帮我看一下我正在调试的东西,他说作为一个通用规则,“不要使用string.empty”,因为它会放在堆栈上,应该将其设置为null。个人而言,我一直使用string.Empty,因为当时它被认为是正确的使用方式,而不是“”。 - user712923
我的意思是... string.Empty""null 都是常量值,但它们都足够“简单”,我不明白为什么你要将其中一个分配给一个变量。如果你需要捕获一个 out 变量,为什么不直接使用 string myString; - stusmith
9
现今,对于那些不注重可读性和语义,而专注于荒谬的微观优化的话题的争论往往是脆弱的。根据具体上下文选择正确的意思(例如,如果你知道某人没有中间名,则使用 String.Empty;如果你不知道某人是否有中间名,则使用 null)。然后,编写清晰正确、易于维护的代码。 - jason
@jason,如果一个人没有中间名字,为什么不使用 null 表示"没有中间名"呢?我将空字符串解释为"有中间名,但为空",这听起来很奇怪。 - OfirD
5个回答

120

nullEmpty 是非常不同的,我不建议随意在它们之间切换。但是两者都没有额外的“成本”,因为Empty是一个单一的固定引用(你可以使用任意次数)。

使用ldsfld 不会在堆栈上造成任何“污染” - 这个担忧是有点疯狂的。加载 null 可能略微更便宜,但如果你不小心检查值,可能会导致空引用异常。

就我个人而言,我两者都不使用... 如果我想要一个空字符串,我使用 "" - 简单明了。由于字符串被纳入,这也没有每次使用的额外开销。


在IL级别上,这里 "" 和 Empty 的区别仅仅是 ldstr vs ldsfld - 但两者都给出相同的单个 interned 字符串引用。此外,在较新的.NET版本中,JIT直接拦截这些操作,产生空字符串引用,而无需实际进行静态字段查找。基本上,除了可读性外,无需关心任何原因。我只使用 ""。


5
如果@user712923提出任何具体的问题,我很乐意听取意见。 - Marc Gravell
5
据我所知,"" 创建一个对象,其中不包含 string.Empty。请查看此链接和此链接。这与字符串内部池有关。 - Jalal Said
7
String.IsNullOrEmpty() 是一个用于检查字符串是否为空或 null 的方法。 - Vinko Vrsalovic
1
使用""代替冗长的样板代码,这是一个好习惯。谁会支持这种无聊的做法?@Jalal,Brad Abrams的帖子已经过时了,如果编译器仍然不能将这两个代码优化为相同的结果,那么微软就应该感到羞耻!但我们不需要去修复他们的工作。实际上,我们也不需要:在第二个链接中,Lasse(在评论中)比较了使用任一变量进行比较的汇编输出:它们是相同的。 - Konrad Rudolph
1
@Jalal 注意我并没有提倡使用new String(new char[]{}),所以你的比较并不适用。此外:“这也与代码有多少字符无关” - 不,从某种程度上来说,它是有关系的。不必要的代码会导致视觉混乱,降低可读性。 - Konrad Rudolph
显示剩余12条评论

42

它并不会“污染堆栈”,虽然没有技术上的原因,但是将一个变量设置为对象的引用(即使是空字符串)和使用 null 是有很大区别的。它们不是同一件事,应该以不同的方式使用。

null 应该用于指示缺少数据,string.Empty(或者 "")则表示存在数据,实际上是空文本。您是否有某种情况不确定何时使用哪种方法最合适?

编辑,添加示例:

  • 您可以将 string.Empty 用作人名的默认后缀(例如,大多数人没有博士学位)

  • 您可以在配置文件中未指定配置选项时使用 null。 在这种情况下,如果配置选项存在但所需的配置值为空字符串,则使用 string.Empty


我得承认,我从没这么想过。鉴于你刚才所说的,你介意给我举个例子吗?我知道你的解释已经很清楚了,但还是谢谢。 - user712923
3
唯一选择一个或另一个的原因是基于你使用它的地方。例如,当你想要使用空字符串时,请使用 string.Empty"",而当你想要指示没有数据时,请使用 null。你可以将 string.Empty 用作人名的默认后缀(大多数人没有博士学位),并将 null 用于未在配置文件中指定的配置选项。在第二种情况下,如果配置选项存在但所需的配置值为空字符串,则使用 string.Empty - Kieren Johnstone
@Kieren Johnstone,如果没有后缀名称,为什么不使用“null”来表示“没有后缀”? - OfirD

9
他们是不同的,正如其他人已经回答过的那样。
static void Main(string[] args)
{
    string s1 = null;
    string s2 = string.Empty;
    string s3 = "";
    Console.WriteLine(s1 == s2);
    Console.WriteLine(s1 == s3);
    Console.WriteLine(s2 == s3);
}

结果:

  1. false - 因为null和string.empty是不同的
  2. false - 因为null和""是不同的
  3. true - 因为""和string.empty相同

在处理空字符串和null字符串时,当您需要将其保存到平面文件或通过通信传输时,这变成了一个问题。因此,我认为为其他访问此页面的人提供特定问题的好解决方案可能会很有用。

为了将字符串保存到文件或通过通信进行通信:
您可能希望将字符串转换为字节。
我建议的一个好习惯是在转换后的字符串中添加2个头字节段。

段1-元信息,存储在1个字节中,并描述下一段的长度。

段2-保存要保存的字符串的长度。

例子:
字符串“abcd”-为了简化起见,我将使用ASCII编码器进行转换,并得到{65,66,67,68}。
计算第2段将产生4-因此4个字节是转换后的字符串的长度。
计算段1将产生1-仅使用1个字节来保存转换后字符串信息的长度(为4,即如果它为260,我将获得2)

现在的新字节序列将是{1,4,65,66,67,68},可以保存到文件中。

就主题而言,优点在于,如果我要保存空字符串,则会从转换中获取长度为0的空字节数组,并在计算段之后最终得到{1,0},可以保存并稍后加载并解释回为空字符串。 另一方面,如果我在字符串中有null值,则最终只会得到{0}作为要保存的字节数组,再次加载时可以解释回null。

还有更多好处,例如知道要加载或累积的大小(如果您拥有多个字符串)。

回到主题-它将……某种程度上会污染栈,因为任何系统都使用相同的原则区分null和empty..。因此是的,string.Empty占用的内存比null多,尽管我不会称其为污染..它只是多了1个字节。


0

这个问题已经被反复回答了,但是 null 表示没有值,而不是未初始化。string.Empty 表示 ""(一个空字符串),正如在 MSDN 上所述。

检查空字符串或 null 的最安全的方法是使用 string.IsNullOrEmpty。


-3

顺便说一下,我发现混合使用""String.Empty不起作用:

var a = "";
alert("a " + (a == "") + ", " + (a==String.Empty));   //Yields "a true, false"

var b = String.Empty;
alert("b " + (b == "") + ", " + (b == String.Empty)); //Yields "b false, true"

特别是,如果您使用$.trim来获取空的DOM输入字段的值,然后将其与String.Empty进行比较,您会得到false。不确定为什么会这样,但就是这样。现在我只是为了一致性而在任何地方使用""

1
是的。这就是为什么我们都应该保持检查.Length==0或使用.Compare()的习惯。 - zanlok
16
这个问题询问的是关于C#而不是JS。 - Cole Tobin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接