为什么我们对以下情况有不同的输出:
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 !?
答案 0 :(得分:7)
答案很简单:
当您将object
与string
进行比较时,会使用参考比较,只有两个对象具有相同的参考时才会生效。
比较字符串时,使用字符串比较,如果字符串内容相同,则无论它们是否是相同的引用,都将为true。
在你的第三次比较中,你正在使用object
比较来比较两个具有相同内容但具有不同引用的字符串,因此它将返回false。
增加的复杂性是前两个字符串具有相同的引用,因为它们是编译时常量并且已经interned
by the compiler,因此它们引用内存中的相同字符串。
我已使用以下解释注释了您的原始代码:
object obj = "Int32"; // As a compile-time constant string, this will be interned.
string str1 = "Int32"; // This is also interned, so has the same reference as obj
string str2 = typeof(int).Name; // Same contents as str1, but a different reference
// (created at runtime, so it wasn't interned)
Console.WriteLine(obj == str1); // Reference comparison: true because the references are the same
Console.WriteLine(str1 == str2); // String comparison: true because the string contents are the same.
Console.WriteLine(obj == str2); // Reference comparison: false because the references different.
此外:
您可以通过声明str2获得相同的结果,如下所示:
string str2 = string.Concat(" Int"," 32");
答案 1 :(得分:1)
obj == str2
行使用参考比较。而obj == str1
行没有。
.NET中的string
类型是隐式引用类型。但它不是在同一时间。它是技术上属于引用类型的那些类型之一,但它被编程为值类型,并且不可变,这意味着它没有直接修改。
当您创建新的string
时,会为其分配一个引用,该引用就是您的string
变量所持有的引用。你可以使用string
做各种各样的事情,但你永远无法改变它。如果重新分配值,它只会创建一个新的引用。
在这种情况下,obj == str1
行使用参考比较,但参考文件实际匹配。因为它们都是硬编码的,所以编译器和.NET可以为每个使用相同的引用。 (正如我们之前所说的,字符串是不可变的。)您应该阅读Matthew发布的interning
链接以获取更多信息。
考虑您可以在内存中创建的重要数量的对象。如果您在任何时候创建了新的string
并且.NET通过所有其他字符串找到匹配的字符串,那么您的程序将非常慢。你几乎不会完成任何真正的工作。
因此,.NET优化了这一点。如果你稍微更改一下代码,你会明白我的意思。
object obj = "Int32";
string str1 = typeof(int).Name;
string str2 = typeof(int).Name;
Console.WriteLine(obj == str1); // false
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // false !?
str1 == str2
行仍然返回true,因为它实际上是比较字符串,而obj == str1
行现在是假的,因为它也在比较那些引用。