空字符串作为特例?

Roy*_*mir 55 .net c#

我读了Jon Skeet的测验,我想知道为什么我的第二个样本在第一个样本时不起作用.

为什么这会产生true:

object x = new string("".ToArray());
object y = new string("".ToArray());
Console.WriteLine(x == y); //true
Run Code Online (Sandbox Code Playgroud)

但是这个没有:

var k="k";
//string.intern(k); // doesn't help
object x = new string(k.ToArray());
object y = new string(k.ToArray());
Console.WriteLine(x == y); //false
Run Code Online (Sandbox Code Playgroud)

我在vs2010上使用fw 4.5.

幸运的是我也安装了vs2005,结果相同:

在此输入图像描述

Mar*_*zek 43

这是Eric Lippert撰写的一篇博文,回答了你的问题:String interning和String.Empty.

他描述了类似的情况:

object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // false !?
Run Code Online (Sandbox Code Playgroud)

所以这个想法是,实习并不意味着你只有一个特定的实例string,即使它是实习的.默认情况下,只会编译时间文字.这意味着以下代码打印为true:

var k1 = "k";
object k2 = "k";
Console.WriteLine(k1 == k2);
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试"k"在运行时以编程方式创建包含内容的字符串,例如使用string(char[])构造函数,调用ToString()对象,使用StringBuilder等,则默认情况下您将不会获得实例化字符串.这个打印假;

var k1 = "k";
object k2 = new string("k".ToCharArray());
Console.WriteLine(k1 == k2);
Run Code Online (Sandbox Code Playgroud)

为什么?因为运行时的实习字符串很昂贵.

没有免费午餐这样的事情.

(......)

简而言之,在一般情况下,不值得实习所有字符串.

关于空字符串的不同行为:

某些版本的.NET运行时会在运行时自动实现空字符串,有些则不会!

  • @Him因为它们被声明为`string`和`String`类重写`==`运算符来执行字符串比较,而不是引用相等检查. (2认同)

Ben*_*enM 11

需要注意的是实习的的代码的第二块串让他们平等的.

var k="k";
object x = string.Intern(new string(k.ToArray()));
object y = string.Intern(new string(k.ToArray()));
Console.WriteLine(x == y); //true
Run Code Online (Sandbox Code Playgroud)

看起来它是自动实现空字符串,但非空字符串不会被实现,除非它们是明确地完成的(或者它们是始终被实现的文字字符串).

我猜是的,空字符串被视为特殊情况并被自动实现,可能是因为检查是如此微不足道,以至于它不会增加任何实际的性能损失(我们可以肯定地说,任何长度为0的字符串都是空字符串并且与任何其他空字符串相同 - 所有其他字符串都要求我们查看字符而不仅仅是长度.

  • 默认情况下,所有常量字符串文字都是实例化的. (3认同)
  • 这返回true,因为你的代码与`object x ="k"相同; 对象y ="k"`默认情况下实习.问题是为什么新的新的`string(k.ToArray())`给出了新的实例,其中`new string("".ToArray())`给出了实例? (2认同)

Pav*_*lev 6

第一种情况比较了对同一对象(String.Empty)的2个引用.调用operator==2个object变量会导致它们通过引用进行比较并给出true.

第二种情况产生2个不同的字符串类实例.他们的参考比较给出false

如果你给string类型xy第二种情况,string.operator==将调用覆盖并进行比较true

请注意,在这两种情况下,我们都不直接处理字符串实习.我们比较的字符串对象是使用string(char[])构造函数创建的.显然,构造函数被设计为string.Empty在使用空数组作为参数调用时返回字段的值.

MarcinJuraszek发布的答案引用了Lippert的博客,该博客讨论了字符串实习.该博客文章讨论了字符串类使用的其他角落案例.考虑前面提到的Lippert博客中的这个例子:

object obj = "";
string str1 = "";
string str2 = String.Empty;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // sometimes true, sometimes false?!
Run Code Online (Sandbox Code Playgroud)

我们在这里看到的是,空字符串literal("")的赋值不能保证产生对静态只读System.String.Empty字段的引用.

让我们看看IL的object x = new string("".ToArray());表达式:

IL_0001:  ldstr      ""
IL_0006:  call       !!0[] [System.Core]System.Linq.Enumerable::ToArray<char>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b:  newobj     instance void [mscorlib]System.String::.ctor(char[])
IL_0010:  stloc.0
Run Code Online (Sandbox Code Playgroud)

实习可能(或可能不)发生在IL_0001线上.无论文本是否被实习,该ToArray()方法都会产生一个新的空数组,并String::.ctor(char[])给出了我们的信息String.Empty.

我们在这里看到的并不是特殊情况,string.Empty而是同时string作为引用类型和不可变类的类的副作用之一.还有其他不可变的框架类型,它们具有类似语义的预定义值(如DateTime.MinValue).但据我所知,这样的框架类型被定义为structstring引用类型不同.值类型是完全不同的故事......从可变类构造函数返回一些固定的预定义类型实例是没有意义的(调用代码将能够更改该实例并导致该类型的不可预测的行为).因此,如果这些类型是不可变的,那么构造函数不总是返回新实例的引用类型可能存在.我不知道框架中的其他类型,除了string.