在 C# 中,我想用一个空字符串初始化一个字符串值。
我该怎么做?什么是正确的方法,为什么?
string willi = string.Empty;
或者
string willi = String.Empty;
或者
string willi = "";
或者是什么?
使用您和您的团队认为最易读的任何内容。
其他答案建议每次使用 ""
时都会创建一个新字符串。这不是真的 - 由于字符串实习,它将在每个程序集或每个 AppDomain 中创建一次(或者可能在整个过程中创建一次 - 在这方面不确定)。这种差异可以忽略不计 - 大量,大量微不足道。
但是,您发现哪个更具可读性是另一回事。这是主观的,并且会因人而异——所以我建议你找出团队中大多数人喜欢的东西,然后为了保持一致。我个人觉得""
更容易阅读。
""
和 " "
很容易被误认为彼此的论点并没有真正与我无关。除非您使用的是比例字体(而且我还没有与 任何 开发人员合作过),否则很容易区分。
从性能和代码生成的角度来看,确实没有区别。在性能测试中,他们在哪一个比另一个更快之间来回切换,而且只差几毫秒。
在查看幕后代码时,您也真的看不出任何区别。唯一的区别在于 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
The best code is no code at all:
编码的基本性质是,作为程序员,我们的任务是认识到我们做出的每一个决定都是一种权衡。 […] 从简洁开始。根据测试要求增加其他尺寸。
因此,代码越少越好:首选 ""
而不是 string.Empty
或 String.Empty
。这两个是 六倍长 没有额外的好处 - 当然没有额外的清晰度,因为它们表达完全相同的信息。
i
is 比长变量名更好。更一般地说,更短的变量名称传达相同的信息,在相同的清晰度下,总是更可取的。只是为了表达您需要特定字符长度的必要信息,我不否认这一点(没有人否认)。
一个区别是,如果使用 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.Empty
与 attributes 一起使用。
我更喜欢 string
而不是 String
。选择 string.Empty
而不是 ""
是选择一个并坚持下去的问题。使用 string.Empty
的优点是您的意思非常明显,而且您不会意外复制 ""
中的 "\x003"
等不可打印字符。
""
很危险的论点是无效的,因为您从不复制/粘贴空字符串。当然,对于其他字符串,它总是需要注意的。
我不打算插话,但我看到一些错误的信息被扔在这里。
我个人更喜欢string.Empty
。这是个人喜好,我会根据具体情况服从与我合作的任何团队的意愿。
正如其他人所提到的,string.Empty
和 String.Empty
之间没有任何区别。
此外,这是一个鲜为人知的事实,使用 "" 是完全可以接受的。在其他环境中,每个 "" 实例都会创建一个对象。但是,.NET 实习其字符串,因此未来的实例将从实习池中提取相同的不可变字符串,任何性能影响都可以忽略不计。来源:Brad Abrams。
string.Empty
和 String.Empty
之间存在差异。第一个使用 C# 语言关键字 string
,因此它始终有效。后者仅适用于文件中的 using System;
。始终首选 string
而不是 String
。
我个人更喜欢“”,除非有充分的理由来处理更复杂的事情。
String.Empty
和 string.Empty
是等价的。 String
是 BCL 类名; string
是它的 C# 别名(或快捷方式,如果你愿意的话)。与 Int32
和 int
相同。有关更多示例,请参阅 the docs。
就 ""
而言,我不太确定。
就个人而言,我总是使用 string.Empty
。
我在 .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
}
这表明所有三个变量,即 str1
、str2
和 str3
,尽管使用不同的语法进行了初始化,但都指向 memory 中相同的字符串(零长度)对象。
所以在内部他们没有区别。这一切都归结为您或您的团队想要使用哪一个的便利性。字符串类的这种行为在 .NET Framework 中称为 string interning。 Eric Lippert 有一个非常好的博客 here 描述了这个概念。
这个话题很老很长,所以如果在其他地方提到过这种行为,请原谅。 (并指出涵盖此的答案)
如果您使用 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
。
几乎每个开发人员都会知道“”是什么意思。我个人第一次遇到 String.Empty 并且不得不花一些时间搜索谷歌以确定它们是否真的是完全相同的东西。
string.Empty
是什么?您知道第一次看到它是什么 ""
吗?
以上任何一种。
有很多很多更好的事情要赞美。比如什么颜色的树皮最适合一棵树,我认为是模糊的棕色,带有淡淡的苔藓色。
我非常喜欢 String.Empty,除了其他原因以确保您知道它是什么并且您没有意外删除内容,但主要是为了国际化。如果我在引号中看到一个字符串,那么我总是想知道这是否是新代码,是否应该将其放入字符串表中。因此,每次更改/审查代码时,您都需要查找“引号中的内容”,是的,您可以过滤掉空字符串,但我告诉人们最好不要将字符串放在引号中,除非您知道它不会被本地化.
没有人提到在 VisualStudio 中字符串的颜色编码与字符串不同。这对于可读性很重要。此外,小写通常用于 vars 和 type,没什么大不了的,但 String.Empty 是一个常量,而不是 var 或类型。
string
是 System.String
类型的同义词,它们是相同的。
值也相同:string.Empty == String.Empty == ""
我不会在代码中使用字符常量“”,而是使用 string.Empty
或 String.Empty
- 更容易理解程序员的意思。
在 string
和 String
之间,我更喜欢小写 string
,因为我曾经使用 Delphi 多年,而 Delphi 风格是小写 string
。
所以,如果我是你的老板,你会写 string.Empty
我更喜欢 string.Empty
而不是 String.Empty
,因为您可以使用它而无需在文件中包含 using System;
。
至于选择 ""
而不是 string.Empty
,这是个人喜好,应该由您的团队决定。
using System
命名空间的情况下使用 string.Empty
常量的人 - C# 中的关键字只需转换为包含命名空间的完全限定名称,然后在输出中写入 MSIL *.dll 或 *.exe 文件。因此,编译器在 MSIL 中有效地将 string.Empty
写为 System.String.Empty
。而且您可能已经知道,如果您提到完全限定的类型名称,那么您可以跳过在代码文件顶部导入命名空间。
我没有区别。最后一个是最快的输入虽然:)
它完全是一种代码风格的偏好,对 .NET 如何处理字符串。但是,这是我的意见:)
在访问静态方法、属性和字段时,我总是使用 BCL 类型名称:String.Empty
或 Int32.TryParse(...)
或 Double.Epsilon
声明新实例时,我总是使用 C# 关键字:int i = 0;
或 string foo = "bar";
我很少使用未声明的字符串文字,因为我希望能够扫描代码以将它们组合成可重用的命名常量。无论如何,编译器都会用文字替换常量,因此这更像是一种避免魔术字符串/数字并用名称赋予它们更多意义的方法。此外,更改值更容易。
没关系——它们是完全一样的。但是,最重要的是你必须保持一致
ps 我一直在为这种“什么是正确的事情”而苦苦挣扎。
我亲眼目睹了两次“”导致(小)问题。一次是由于一个刚接触基于团队的编程的初级开发人员的错误,另一个是一个简单的错字,但事实是使用 string.Empty 可以避免这两个问题。
是的,这在很大程度上是一个判断要求,但是当一种语言为您提供多种做事方式时,我倾向于倾向于编译器监督最多且编译时执行力最强的语言。那不是 ””。这一切都是为了表达特定的意图。
如果您键入 string.EMpty 或 Strng.Empty,编译器会让您知道您做错了。立即地。它根本不会编译。作为开发人员,您引用了编译器(或其他开发人员)不能以任何方式误解的特定意图,并且当您做错时,您无法创建错误。
如果您输入“”,而您的意思是“”,反之亦然,编译器会愉快地执行您告诉它的操作。其他开发人员可能也可能无法收集您的特定意图。已创建错误。
早在 string.Empty 出现之前,我就使用了定义 EMPTY_STRING 常量的标准库。在不允许 string.Empty 的 case 语句中,我们仍然使用该常量。
只要有可能,让编译器为您工作,并消除人为错误的可能性,无论多么小。 IMO,正如其他人所引用的那样,这胜过“可读性”。
特异性和编译时执行。这是晚饭吃的。
我使用第三个,但在其他两个中,第一个似乎不那么奇怪。 string 是 String 的别名,但在作业中看到它们会让人感觉不舒服。
前两个中的任何一个对我来说都是可以接受的。我会避免使用最后一个,因为通过在引号之间放置一个空格相对容易引入错误。通过观察很难找到这个特殊的错误。假设没有错别字,所有在语义上都是等价的。
[编辑]
此外,您可能希望始终使用 string
或 String
以保持一致性,但这只是我。
我只是在看一些代码,这个问题突然出现在我的脑海中,我之前读过一段时间。这当然是可读性的问题。
考虑以下 C# 代码...
(customer == null) ? "" : customer.Name
对比
(customer == null) ? string.empty : customer.Name
我个人觉得后者不那么模棱两可,更容易阅读。
正如其他人指出的那样,实际差异可以忽略不计。
从长远来看,编译器应该使它们都相同。选择一个标准,以便您的代码易于阅读,并坚持下去。
虽然差异非常非常小,但差异仍然存在。
1) "" 创建对象,而 String.Empty 没有。但是这个对象将被创建一次,如果代码中有另一个“”,稍后将从字符串池中引用。
2)字符串和字符串是相同的,但我建议使用 String.Empty(以及 String.Format、String.Copy 等),因为点表示法表示类,而不是运算符,并且类以大写字母开头符合C# 编码标准。
我使用“”是因为它在我的代码中会被染成明显的黄色......由于某种原因,String.Empty 在我的 Visual Studio Code 主题中全是白色。我相信这对我来说最重要。
我认为第二个是“适当的”,但老实说,我认为这并不重要。编译器应该足够聪明,可以将其中的任何一个编译成完全相同的字节码。我自己使用“”。
在 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 ...我的关心水平很低 ;-)
空字符串就像空集,只是每个人用来调用 ""
的名称。同样在正式语言中,从长度为零的字母表创建的字符串称为空字符串。 set 和 string 都有一个特殊的符号。空字符串:ε 和空集:∅。如果你想谈论这个零长度的字符串,你会称它为空字符串,这样每个人都知道你指的是什么。现在,如果您将其命名为空字符串,为什么不在代码中使用 string.Empty
,它表明意图是明确的。缺点是它不是一个常数,因此并非在任何地方都可用,比如在属性中。 (由于某些技术原因,它不是一个常数,请参阅参考资料。)
可能是一个有争议的评论,但总的来说,我发现当我与 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("")>
string.Empty
is not a constant。这意味着在许多需要编译时常量的情况下,string.Empty
甚至是不合法的。这包括switch
语句中的case ""
块、可选参数的默认值、应用属性的参数和属性,以及许多其他情况(留给读者)。因此,鉴于在某些常见情况下不允许使用string.Empty
,最好使用""
-everywhere 约定。