ChatGPT解决这个技术问题 Extra ChatGPT

在 C# 中,我应该使用 string.Empty 或 String.Empty 还是 "" 来初始化字符串?

在 C# 中,我想用一个空字符串初始化一个字符串值。

我该怎么做?什么是正确的方法,为什么?

string willi = string.Empty;

或者

string willi = String.Empty;

或者

string willi = "";

或者是什么?

另请参阅 java 的类似讨论:stackoverflow.com/questions/213985/…
当然,最好使用 String.IsNullOrEmpty(string myString) 吗?
我使用 [string.IsNullOrWhiteSpace(stringvalue)] ... 适用于 .Net 4.0。要初始化,我只需使用: [var text = "";] 简单、易读且输入时间最少:)
更重要的是变量的有趣名称。
让我感兴趣的是,为什么还有一个 Empty 属性。这很好,一切都很好,但不是必要的和完全的必须。

O
Otiel

使用您和您的团队认为最易读的任何内容。

其他答案建议每次使用 "" 时都会创建一个新字符串。这不是真的 - 由于字符串实习,它将在每个程序集或每个 AppDomain 中创建一次(或者可能在整个过程中创建一次 - 在这方面不确定)。这种差异可以忽略不计 - 大量,大量微不足道。

但是,您发现哪个更具可读性是另一回事。这是主观的,并且会因人而异——所以我建议你找出团队中大多数人喜欢的东西,然后为了保持一致。我个人觉得""更容易阅读。

""" " 很容易被误认为彼此的论点并没有真正与我无关。除非您使用的是比例字体(而且我还没有与 任何 开发人员合作过),否则很容易区分。


当您期望看到“”时,您的眼睛会欺骗您,您很容易将“”误认为“”。这就是为什么编辑别人写的东西更容易的原因。你的大脑对文本没有先入为主的想法,因此更容易找出异常。
@tvanfosson:那么您(或您的同事)实际上是否被这个错误所困扰?我怀疑这种说法,但实际上并没有引起问题。多年来我一直在使用“”,但从未弄错...
就个人而言,我一直使用 String.Empty,每当我想对字符串使用静态方法时,我都会使用大写的“S”,这只是个人偏好,可以让我区分类型和变量。但这只是在 java 的 commons.lang 中使用 StringUtils.EMPTY 的结果。有趣的一点是我几乎是盲人,这肯定有助于我的可读性。
您给了我在 Times New Roman 开始开发的灵感。
对于一些obscure reason string.Empty is not a constant。这意味着在许多需要编译时常量的情况下,string.Empty 甚至是不合法的。这包括 switch 语句中的 case "" 块、可选参数的默认值、应用属性的参数和属性,以及许多其他情况(留给读者)。因此,鉴于在某些常见情况下不允许使用 string.Empty,最好使用 ""-everywhere 约定。
B
Blorgbeard

从性能和代码生成的角度来看,确实没有区别。在性能测试中,他们在哪一个比另一个更快之间来回切换,而且只差几毫秒。

在查看幕后代码时,您也真的看不出任何区别。唯一的区别在于 IL,其中 string.Empty 使用操作码 ldsfld"" 使用操作码 ldstr,但这只是因为 string.Empty 是静态的,并且两条指令执行相同的操作。如果您查看生产的组件,它是完全相同的。

C# 代码

private void Test1()
{
    string test1 = string.Empty;    
    string test11 = test1;
}

private void Test2()
{
    string test2 = "";    
    string test22 = test2;
}

IL代码

.method private hidebysig instance void 
          Test1() cil managed
{
  // Code size       10 (0xa)
  .maxstack  1
  .locals init ([0] string test1,
                [1] string test11)
  IL_0000:  nop
  IL_0001:  ldsfld     string [mscorlib]System.String::Empty
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ret
} // end of method Form1::Test1
.method private hidebysig instance void 
        Test2() cil managed
{
  // Code size       10 (0xa)
  .maxstack  1
  .locals init ([0] string test2,
                [1] string test22)
  IL_0000:  nop
  IL_0001:  ldstr      ""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ret
} // end of method Form1::Test2

汇编代码

        string test1 = string.Empty;
0000003a  mov         eax,dword ptr ds:[022A102Ch] 
0000003f  mov         dword ptr [ebp-40h],eax 

        string test11 = test1;
00000042  mov         eax,dword ptr [ebp-40h] 
00000045  mov         dword ptr [ebp-44h],eax 
        string test2 = "";
0000003a  mov         eax,dword ptr ds:[022A202Ch] 
00000040  mov         dword ptr [ebp-40h],eax 

        string test22 = test2;
00000043  mov         eax,dword ptr [ebp-40h] 
00000046  mov         dword ptr [ebp-44h],eax 

@PrateekSaluja:要查看 IL,您可以使用 Visual Studio 附带的 ildasm.exe。要查看反汇编,请在遇到断点时使用调试菜单上的“反汇编”窗口(也适用于发布代码)。
讨厌我要推荐这个产品..但是..反射器让你在反汇编源代码时选择你的语言,IL是一个选项! ILDASM 只是过时的感觉...... MS 工具团队似乎没有打磨或发布好的工具!
K
Konrad Rudolph

The best code is no code at all

编码的基本性质是,作为程序员,我们的任务是认识到我们做出的每一个决定都是一种权衡。 […] 从简洁开始。根据测试要求增加其他尺寸。

因此,代码越少越好:首选 "" 而不是 string.EmptyString.Empty。这两个是 六倍长 没有额外的好处 -  当然没有额外的清晰度,因为它们表达完全相同的信息。


但在 C# 中我们可以只说 string.IsNullOrWhitespace(s) :p
我同意代码应该尽可能小,但通常不会争辩说更少的字符总是更好的代码。例如,当涉及到变量命名时,合理数量的字符通常会产生比仅使用 i 和 j 更好的名称。
@Markus 这高度依赖:对于表示索引的循环变量,i is 比长变量名更好。更一般地说,更短的变量名称传达相同的信息,在相同的清晰度下,总是更可取的。只是为了表达您需要特定字符长度的必要信息,我不否认这一点(没有人否认)。
@Konrad:仅当循环很小且不包含任何其他索引时, i 才是一个好的变量名。但我同意,如果……。可以更简单地说明传达相同的信息,这将是可取的,例如在 string.Empty / "" 情况下。 string.Empty 不会增加任何清晰度。
对我来说:string.Empty 表示这个字符串在任何时候都是并且应该是空的,而 "" 表示在编写这个字符串时可能是空的,但您可以自由更改它。
K
Kolappan N

一个区别是,如果使用 switch-case 语法,则不能编写 case string.Empty:,因为它不是常量。你得到一个Compilation error : A constant value is expected

查看此链接了解更多信息:string-empty-versus-empty-quotes


switch 语句就是一个很好的例子。此外,如果您制作一个可选参数,例如 void MyMethod(string optional = "") { ... },则也无法使用 string.Empty。当然,如果您想定义 const 字段或局部变量,const string myString = "";"" 是唯一的选择。如果只有 string.Empty 是一个常量字段,则不会有区别。但事实并非如此,因此在某些情况下您必须使用 ""。那么为什么不一直使用 "" 呢?
这是一个非常有力的论据,因为使用 string.Empty 会阻止您在代码库中获得一致性:您必须使用两个不同的实体来表达同一事物。并且添加到您不能做的事情列表中:您不能将 string.Emptyattributes 一起使用。
非常好的点!链接已损坏。这是内容的副本:web.archive.org/web/20131230161806/http://kossovsky.net/…
C
CodesInChaos

我更喜欢 string 而不是 String。选择 string.Empty 而不是 "" 是选择一个并坚持下去的问题。使用 string.Empty 的优点是您的意思非常明显,而且您不会意外复制 "" 中的 "\x003" 等不可打印字符。


我认为如果你不小心将不可打印的字符复制到你的代码中,你会遇到比这个问题更大的问题;)
ASCII \003 恰好是我使用过的 B2B 消息的字段分隔符:)
(顺便说一句,我还建议避免 \x 转义 - 很难发现“\x9Bad Compiler”和“\x9Good Compiler”之间的区别,它们的结果完全不同!)
就我个人而言,每当在 String 上调用静态方法时,我更喜欢 String 而不是字符串。然而,我几乎是盲人,这是个人偏好,我不会强加于任何人。
@Jimmy 当然,但我们谈论的是空字符串。我声称,当复制/粘贴时 "" 很危险的论点是无效的,因为您从不复制/粘贴空字符串。当然,对于其他字符串,它总是需要注意的。
B
Brian Leahy

我不打算插话,但我看到一些错误的信息被扔在这里。

我个人更喜欢string.Empty。这是个人喜好,我会根据具体情况服从与我合作的任何团队的意愿。

正如其他人所提到的,string.EmptyString.Empty 之间没有任何区别。

此外,这是一个鲜为人知的事实,使用 "" 是完全可以接受的。在其他环境中,每个 "" 实例都会创建一个对象。但是,.NET 实习其字符串,因此未来的实例将从实习池中提取相同的不可变字符串,任何性能影响都可以忽略不计。来源:Brad Abrams


我不明白为什么“技术上”的每个“”实例都会创建一个对象。字符串被实习不仅仅是机会 - 它在 C# 规范中。
string.EmptyString.Empty 之间存在差异。第一个使用 C# 语言关键字 string,因此它始终有效。后者仅适用于文件中的 using System;。始终首选 string 而不是 String
M
MidnightGun

我个人更喜欢“”,除非有充分的理由来处理更复杂的事情。


P
Palec

String.Emptystring.Empty 是等价的。 String 是 BCL 类名; string 是它的 C# 别名(或快捷方式,如果你愿意的话)。与 Int32int 相同。有关更多示例,请参阅 the docs

"" 而言,我不太确定。

就个人而言,我总是使用 string.Empty


R
RBT

我在 .NET v4.5 控制台应用程序中使用以下方法执行了一个简单的测试:

private static void CompareStringConstants()
{
    string str1 = "";
    string str2 = string.Empty;
    string str3 = String.Empty;
    Console.WriteLine(object.ReferenceEquals(str1, str2)); //prints True
    Console.WriteLine(object.ReferenceEquals(str2, str3)); //prints True
}

这表明所有三个变量,即 str1str2str3,尽管使用不同的语法进行了初始化,但都指向 memory 中相同的字符串(零长度)对象。

所以在内部他们没有区别。这一切都归结为您或您的团队想要使用哪一个的便利性。字符串类的这种行为在 .NET Framework 中称为 string interning。 Eric Lippert 有一个非常好的博客 here 描述了这个概念。


S
Steve

这个话题很老很长,所以如果在其他地方提到过这种行为,请原谅。 (并指出涵盖此的答案)

如果您使用 string.Empty 或双引号,我发现编译器的行为有所不同。如果您不使用使用 string.Empty 或双引号初始化的字符串变量,差异就会显现出来。

如果使用 string.Empty 进行初始化,则编译器警告

CS0219 - The variable 'x' is assigned but its value is never used

永远不会发出,而在使用双引号进行初始化的情况下,您会收到预期的消息。

此行为在此链接的 Connect 文章中进行了说明:https://connect.microsoft.com/VisualStudio/feedback/details/799810/c-warning-cs0219-not-reported-when-assign-non-constant-value

基本上,如果我做对了,他们希望允许程序员使用函数的返回值设置一个变量以用于调试目的,而不会用警告消息打扰他,因此他们仅在成本分配和字符串的情况下限制警告。空不是一个常数,而是一个字段。


我相信你是第一个提到的。几个月前我通读了这个问答,不记得这个区别,如果有人提到的话,我会的。
有趣的。请注意,声明 var unused = "literal"; 可以被编译器完全优化掉(删除)。它可以没有副作用。另一方面,不能完全删除 var unused = MyClass.Member;。那是因为阅读 Member 可能会产生副作用。如果 Member 是具有 get 访问器的静态属性,那么显然必须保留对 getter 的调用。但即使 Member 是静态字段,也可能存在静态构造函数可能运行的副作用。当然,如果采用这种方式,那将是糟糕的编码风格。但是你需要一个假人来阅读 Member
J
Jason Baker

几乎每个开发人员都会知道“”是什么意思。我个人第一次遇到 String.Empty 并且不得不花一些时间搜索谷歌以确定它们是否真的是完全相同的东西。


它是一个公共的只读字符串字段,它的值为“”......为什么会改变?
你错过了@Jason 提出的观点。您怎么知道第一次看到 string.Empty 是什么?您知道第一次看到它是什么 "" 吗?
Q
Quibblesome

以上任何一种。

有很多很多更好的事情要赞美。比如什么颜色的树皮最适合一棵树,我认为是模糊的棕色,带有淡淡的苔藓色。


佚名

我非常喜欢 String.Empty,除了其他原因以确保您知道它是什么并且您没有意外删除内容,但主要是为了国际化。如果我在引号中看到一个字符串,那么我总是想知道这是否是新代码,是否应该将其放入字符串表中。因此,每次更改/审查代码时,您都需要查找“引号中的内容”,是的,您可以过滤掉空字符串,但我告诉人们最好不要将字符串放在引号中,除非您知道它不会被本地化.


D
Dimitry

没有人提到在 VisualStudio 中字符串的颜色编码与字符串不同。这对于可读性很重要。此外,小写通常用于 vars 和 type,没什么大不了的,但 String.Empty 是一个常量,而不是 var 或类型。


String.Empty 不是常量:请参阅 stackoverflow.com/questions/507923/… 它实际上是 String 类的一个实例,这是设计的。之前提到过着色,虽然有点隐蔽:stackoverflow.com/questions/263191/…
z
zendar

stringSystem.String 类型的同义词,它们是相同的。

值也相同:string.Empty == String.Empty == ""

我不会在代码中使用字符常量“”,而是使用 string.EmptyString.Empty - 更容易理解程序员的意思。

stringString 之间,我更喜欢小写 string,因为我曾经使用 Delphi 多年,而 Delphi 风格是小写 string

所以,如果我是你的老板,你会写 string.Empty


R
RBT

我更喜欢 string.Empty 而不是 String.Empty,因为您可以使用它而无需在文件中包含 using System;

至于选择 "" 而不是 string.Empty,这是个人喜好,应该由您的团队决定。


我是团队中唯一的成员,我该如何决定?掷骰子?
对于那些可能想知道如何在不导入 using System 命名空间的情况下使用 string.Empty 常量的人 - C# 中的关键字只需转换为包含命名空间的完全限定名称,然后在输出中写入 MSIL *.dll 或 *.exe 文件。因此,编译器在 MSIL 中有效地将 string.Empty 写为 System.String.Empty。而且您可能已经知道,如果您提到完全限定的类型名称,那么您可以跳过在代码文件顶部导入命名空间。
佚名

我没有区别。最后一个是最快的输入虽然:)


m
mckamey

它完全是一种代码风格的偏好,对 .NET 如何处理字符串。但是,这是我的意见:)

在访问静态方法、属性和字段时,我总是使用 BCL 类型名称:String.EmptyInt32.TryParse(...)Double.Epsilon

声明新实例时,我总是使用 C# 关键字:int i = 0;string foo = "bar";

我很少使用未声明的字符串文字,因为我希望能够扫描代码以将它们组合成可重用的命名常量。无论如何,编译器都会用文字替换常量,因此这更像是一种避免魔术字符串/数字并用名称赋予它们更多意义的方法。此外,更改值更容易。


C
Calanus

没关系——它们是完全一样的。但是,最重要的是你必须保持一致

ps 我一直在为这种“什么是正确的事情”而苦苦挣扎。


在现代世界中,“一致”意味着在全球所有团队中保持一致,这是 StackOverflow 的目标之一。如果我可以建议,让我们使用 String.Empty。
有些语言没有 Empty 常量,我能想到的所有语言都允许 "" 一个零长度字符串。所以我投票支持“”以与其他语言保持一致。 :)
R
RhinoTX

我亲眼目睹了两次“”导致(小)问题。一次是由于一个刚接触基于团队的编程的初级开发人员的错误,另一个是一个简单的错字,但事实是使用 string.Empty 可以避免这两个问题。

是的,这在很大程度上是一个判断要求,但是当一种语言为您提供多种做事方式时,我倾向于倾向于编译器监督最多且编译时执行力最强的语言。那不是 ””。这一切都是为了表达特定的意图。

如果您键入 string.EMpty 或 Strng.Empty,编译器会让您知道您做错了。立即地。它根本不会编译。作为开发人员,您引用了编译器(或其他开发人员)不能以任何方式误解的特定意图,并且当您做错时,您无法创建错误。

如果您输入“”,而您的意思是“”,反之亦然,编译器会愉快地执行您告诉它的操作。其他开发人员可能也可能无法收集您的特定意图。已创建错误。

早在 string.Empty 出现之前,我就使用了定义 EMPTY_STRING 常量的标准库。在不允许 string.Empty 的 case 语句中,我们仍然使用该常量。

只要有可能,让编译器为您工作,并消除人为错误的可能性,无论多么小。 IMO,正如其他人所引用的那样,这胜过“可读性”。

特异性和编译时执行。这是晚饭吃的。


p
plinth

我使用第三个,但在其他两个中,第一个似乎不那么奇怪。 string 是 String 的别名,但在作业中看到它们会让人感觉不舒服。


t
tvanfosson

前两个中的任何一个对我来说都是可以接受的。我会避免使用最后一个,因为通过在引号之间放置一个空格相对容易引入错误。通过观察很难找到这个特殊的错误。假设没有错别字,所有在语义上都是等价的。

[编辑]

此外,您可能希望始终使用 stringString 以保持一致性,但这只是我。


我同意这句话,但我懒惰的时候仍然过着危险的生活。无论如何,我认为在变量声明之外分配给它之前,我没有机会编写使用字符串的代码。事实上,尽管有风险,但我必须初始化我的字符串,这让我很恼火。
R
Remotec

我只是在看一些代码,这个问题突然出现在我的脑海中,我之前读过一段时间。这当然是可读性的问题。

考虑以下 C# 代码...

(customer == null) ? "" : customer.Name

对比

(customer == null) ? string.empty : customer.Name

我个人觉得后者不那么模棱两可,更容易阅读。

正如其他人指出的那样,实际差异可以忽略不计。


C
Chris Marasti-Georg

从长远来看,编译器应该使它们都相同。选择一个标准,以便您的代码易于阅读,并坚持下去。


u
user34577

虽然差异非常非常小,但差异仍然存在。

1) "" 创建对象,而 String.Empty 没有。但是这个对象将被创建一次,如果代码中有另一个“”,稍后将从字符串池中引用。

2)字符串和字符串是相同的,但我建议使用 String.Empty(以及 String.Format、String.Copy 等),因为点表示法表示类,而不是运算符,并且类以大写字母开头符合C# 编码标准。


string.Empty 为“”,查看来源
5
5argon

我使用“”是因为它在我的代码中会被染成明显的黄色......由于某种原因,String.Empty 在我的 Visual Studio Code 主题中全是白色。我相信这对我来说最重要。


M
Magus

我认为第二个是“适当的”,但老实说,我认为这并不重要。编译器应该足够聪明,可以将其中的任何一个编译成完全相同的字节码。我自己使用“”。


O
Otiel

http://blogs.msdn.com/b/brada/archive/2003/04/22/49997.aspx 上:

正如大卫暗示的那样,String.Empty 和 "" 之间的区别很小,但还是有区别的。 "" 实际上创建了一个对象,它很可能会从字符串实习生池中被拉出,但仍然......而 String.Empty 没有创建对象......所以如果你真的在寻找最终的内存效率,我建议使用 String.Empty。空的。但是,您应该记住差异是如此微不足道,您将永远不会在您的代码中看到它...至于 System.String.Empty 或 string.Empty 或 String.Empty ...我的关心水平很低 ;-)


那个 MSDN 博客文章是在 2003 年......你确定这对于最近的 .NET 版本仍然适用吗?!
@CarstenSchütte:在我看来,这样的功能并没有太大的改变......如果是的话,互联网上有一些关于它的嗡嗡声。
@sergiol如果一个字段比文字更有效,那么这无疑是一个性能错误。所以现在希望它会被修复。
W
Wouter

空字符串就像空集,只是每个人用来调用 "" 的名称。同样在正式语言中,从长度为零的字母表创建的字符串称为空字符串。 set 和 string 都有一个特殊的符号。空字符串:ε 和空集:∅。如果你想谈论这个零长度的字符串,你会称它为空字符串,这样每个人都知道你指的是什么。现在,如果您将其命名为空字符串,为什么不在代码中使用 string.Empty,它表明意图是明确的。缺点是它不是一个常数,因此并非在任何地方都可用,比如在属性中。 (由于某些技术原因,它不是一个常数,请参阅参考资料。)


K
Keith Howard

可能是一个有争议的评论,但总的来说,我发现当我与 Microsoft 保持一致时,我的生活会更轻松。我们不可能知道他们为什么做事的全部深层原因(有时非常严格,有时很笨拙,我想)。

他们在自动生成的文件(如程序集文件)中使用“”,这就是我所做的。事实上,当我尝试用 String.Empty 替换 "" 以下的任何内容时,Visual Studio 崩溃了。对此可能有一个合乎逻辑的解释,但以我有限的知识,如果我只是按照他们所做的那样做,大多数情况下,事情都会解决。 (相反:我知道他们一些自动生成的文件也使用 String.Empty,这打破了我的观点。:))

<Assembly: System.Reflection.AssemblyCulture("")>
<Assembly: System.Reflection.AssemblyDescription("")>
<Assembly: System.Reflection.AssemblyFileVersion("1.0.0.0")>
<Assembly: System.Reflection.AssemblyKeyFile("")>
<Assembly: System.Reflection.AssemblyProduct("")>
<Assembly: System.Reflection.AssemblyTitle("")>

通过阅读其他答案并花时间真正理解它们来扩展您的知识。 :-) 与您的代码库的其余部分和其他代码库(.NET 本身,生成的代码......)保持一致性是一个很好的经验法则,但它并不总是明确适用,有时甚至是有害的——例如,您需要做一些非常具体的事情,或者您是第一个发现团队当前实践中存在缺陷的人。此外,与您不理解的内容保持一致可能会导致cargo cult programming