我在网站上找到了如下代码。
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
这里,再次投射到对象类型的目的是什么,因为a,b,d本身就是字符串的对象?
答案 0 :(得分:24)
C#编译器将尝试在编译时获取所有常量字符串。这称为字符串实习。因此,生成的代码a
和b
引用后,相同的字符串包含" xx"。
您可以通过比较它们的引用(将它们转换为对象并进行相等性检查或使用object.ReferenceEquals
)来检查这一点。请记住,==
字符串运算符会比较它们的值而不是它们的引用。
另一件需要提及的是.NET中的strings are immutable。
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
那么Console.WriteLine((object)a == c);
为什么要进行参考检查?因为编译器会在对象上选择==
运算符来检查引用相等性。
因此,在您的问题中投射到对象的重点是检查字符串实习是否有效。 假设编译时没有实习。
string a = "xx";
string b = "xx";
string c = "x";
string d = String.Intern(c + c);
然后Console.WriteLine((object)a == (object)b);
将打印" False",因为a
和b
是引用两个不同的字符串强>在记忆中,两者都看起来像" xx"。
答案 1 :(得分:6)
对提供的答案的补充: string (C# Reference)
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
<强>结果:强>
True
False
False
<强>解释强>:
这将创建一个新对象:
string a = "hello";
这将创建另一个对象:
string b = "h";
这将创建另一个对象:
b += "ello";
以下将创建对现有对象的引用,更确切地说,它将指向变量“a”指向→“hello”的同一对象。
string c = "hello";
Console.WriteLine (object.ReferenceEquals(a,c)); // --> TRUE
字符串是不可变的 - 字符串对象的内容不能 创建对象后更改,尽管语法可以实现 好像你可以这样做。例如,当您编写此代码时, 编译器实际上创建了一个新的字符串对象来保存新的 字符序列,并将新对象分配给b。该 字符串“h”然后有资格进行垃圾收集。
答案 2 :(得分:5)
C#使用==
标记来表示三个不同的运算符:一个可重载的等式检查运算符(如果对于所讨论的确切类型存在重载,则可用于类类型或值类型),不可重载的引用标识-check运算符(要求两个操作数都是类引用,并要求类型不相互排斥),以及一个空检查运算符(可用于任何类类型,可空值类型或泛型,可能是其中之一)以上)。虽然大多数形式的重载是在.NET语言中以统一的方式定义的,但是对于所有这三种相等使用一个运算符则不然。其他语言如VB.NET对第一种形式使用不同的标记(例如,在VB.NET中,表达式(x = y)
使用相等测试重载(如果定义了一个),或者如果没有则生成语法错误; {{1测试(x Is y)
和x
是否标识相同的对象实例,而不考虑是否存在重载的相等运算符。
转换为y
的目的是确保Object
标记被解释为表示reference-identity-check运算符而不是可重载的等于运算符;只有因为C实现==
运算符的方式才需要这样的强制转换,而在VB.NET等其他语言中则不需要。
答案 3 :(得分:1)
评论代码
因此,如果值“xx”在运行时设置为相同的“xx”值,那么您将得到不同的false结果,因为编译器没有机会在运行时进行优化,即使它是两种情况下的代码和输入值相同,预编译与运行时的结果不同。
private void button1_Click(object sender, EventArgs e)
{
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
}
private void button2_Click(object sender, EventArgs e)
{
string a = textBox1.Text; //type in xx at runtime
string b = textBox2.Text; //type in xx at runtime
string c = textBox3.Text; //type in just "x" at runtime
string d = String.Intern(c + c);
Console.WriteLine((object)a == (object)b); // False with runtime values that have the same value
Console.WriteLine((object)a == (object)d); // False
Console.WriteLine(a == d); // True - the Equals Operator of the string works as expected still
}