投入"对象"类型的目的是什么?

Bab*_*boB 19 .net c# string equality string-interning

我在网站上找到了如下代码.

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);

 Console.WriteLine((object)a == (object)b); // True
 Console.WriteLine((object)a == (object)d); // True
Run Code Online (Sandbox Code Playgroud)

在这里,再次投射到对象类型的目的是什么,因为a,b,d本身就是字符串的对象?

Ham*_*jam 24

C#编译器将尝试在编译时获取所有常量字符串.这称为字符串实习.所以在生成代码之后a,b它们是包含"xx" 的相同字符串的引用.

您可以通过比较它们的引用(将它们转换为对象并进行相等性检查或使用object.ReferenceEquals)来检查这一点.请记住,==字符串运算符比较它们的值而不是它们的引用.

另外要提到的是字符串在.NET中是不可变的.

string a = "xx";
string b = "x" + "x"; // String interning here
string c = string.Join("", new[] { "x", "x" }); // No interning here because it is evaluated at runtime

Console.WriteLine((object)a == (object)b); // True. Reference check
Console.WriteLine(a == b); // True. Value check

Console.WriteLine((object)a == c); //False. Reference check. Described below
Console.WriteLine(a == c); // True. Value check
Run Code Online (Sandbox Code Playgroud)

那么为什么Console.WriteLine((object)a == c);要做参考检查?因为编译器会==在对象上选择运算符来检查引用相等性.


因此,在您的问题中投射到对象的重点是检查字符串实习是否有效.假设编译时没有实习.

 string a = "xx";
 string b = "xx";
 string c = "x";
 string d = String.Intern(c + c);
Run Code Online (Sandbox Code Playgroud)

然后Console.WriteLine((object)a == (object)b);将打印"False",因为a并且b是内存中两个不同字符串的引用,两者都看起来像"xx".

  • [Operator ==](http://referencesource.microsoft.com/#mscorlib/system/string.cs,661)对字符串进行值检查.@Carl (3认同)

Leg*_*nds 6

对提供的答案的补充: 字符串(C#参考)

System.String类是不可变的引用类型在.NET框架类库提供.此类在内部为任何字符串操作操作创建新的字符串对象.虽然语法使得它看起来好像可以更改内容,但此类对象的内容不会更改.此外,字符串用作哈希表键以计算哈希值,以避免破坏哈希数据结构的风险.

例:

string a = "hello";
string b = "h";

// Append to contents of 'b'
b += "ello";
// When you set the variable's b value to "hello", 
// this would result in changing the pointer
// to the object in the HEAP the variable "a" is already pointing to
// Result would be: (reference of a == reference of b) --> TRUE
// b = "hello"; 

Console.WriteLine(a == b);                       // value comparison
Console.WriteLine((object)a == (object)b);       // reference comparison
Console.WriteLine (object.ReferenceEquals(a,b)); // reference comparison without casting
Run Code Online (Sandbox Code Playgroud)

结果:

True
False
False
Run Code Online (Sandbox Code Playgroud)

说明:

这将创建一个新对象:

string a = "hello";
Run Code Online (Sandbox Code Playgroud)

这将创建另一个对象:

string b = "h"; 
Run Code Online (Sandbox Code Playgroud)

这将创建另一个对象:

b += "ello";
Run Code Online (Sandbox Code Playgroud)

下面将创建对现有对象的引用,更准确地说,它将指向变量"a"指向→"hello"的同一对象.

string c = "hello"; 
Console.WriteLine (object.ReferenceEquals(a,c)); // --> TRUE
Run Code Online (Sandbox Code Playgroud)

字符串是不可变的 - 创建对象后,字符串对象的内容无法更改,尽管语法使其看起来好像可以执行此操作.例如,当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给b.然后字符串"h"有资格进行垃圾回收.

  • 您不应该提到堆或堆栈,因为这些是.NET运行时的实现细节,并且可能因不同版本而异.[堆和堆栈](https://blogs.msdn.microsoft.com/ericlippert/2010/09/30/the-truth-about-value-types/) (2认同)

sup*_*cat 5

C#使用==令牌来表示三个不同的运算符:一个可重载的相等检查运算符(如果对于所讨论的确切类型存在重载,则可用于类类型或值类型),一个不可重载的引用标识检查运算符(这需要两者都有)操作数是类引用,并要求类型不是互斥的),以及一个空检查操作符(可用于任何类类型,可空值类型或可能是上述之一的泛型).虽然大多数形式的重载是在.NET语言中以统一的方式定义的,但是对于所有这三种相等使用一个运算符则不然.像VB.NET其它语言使用不同的令牌针对第一形式(例如在VB.NET,表达(x = y)使用如果定义一个相等测试过载,或生成语法错误若否; (x Is y)测试是否xy识别相同的对象实例不考虑是否存在重载的相等运算符).

强制转换的目的Object是确保==令牌被解释为表示reference-identity-check运算符而不是可重载的等于运算符; 这样的强制转换只是因为C实现了==运算符,而在VB.NET等其他语言中是不需要的.