C#编译时字符串连接

21
请帮助理解这个行为。当我使用以下代码时:
bool a1 = (object)("string" + 1) == ("string" + 1);

结果为false

但是当我使用这个时

bool a2 = (object)("string" + "1") == ("string" + "1"); 

结果为true

那么,为什么是a1 != a2呢?


我不确定为什么,但是我知道你不应该使用“==”来检查字符串的相等性。object1.equals(object2) 是正确的方法,至少在我的理解中是这样的。虽然这可能并没有回答你的问题,但我还是把它写下来了。 - Ricky Mutschlechner
请查看此链接:https://dev59.com/h3A75IYBdhLWcg3wP2gg - Ani
1
据我所知,运算符“==”等同于“.equals”。;-) - Fabian Bigler
11
在C#中,如果两个字符串被视为字符串,使用==来比较是可以的,这只是在处理作为对象强制转换的字符串时有点奇怪。但是,"string" + 1 == "string1"仍然返回true。而在Java中,你确实需要使用equals。我避免在.NET中使用Equals的最大原因是每次都要检查第一个字符串是否为空,以避免NullReferenceException,而使用==可以很好地比较空值。 - Joe Enos
@FabianBigler 很好知道!我肯定是一个Java用户,最近才开始使用C#,但这绝对是我会记在心里的事情。谢谢分享! - Ricky Mutschlechner
@RickyMutschlechner 没问题。确保你也读了Joe Enos的评论(它很有启发性,提出了一些不错的想法)。 - Fabian Bigler
2个回答

34

将类型转换为object会强制进行引用相等性比较。

在第一种情况下,运行时生成了两个不同的string对象。由于它们是不同的实例,所以结果为false。

在第二种情况下,编译器注意到"string" + "1"总是会变成"string1",并在两个位置使用同一个字符串引用。由于它是相同的字符串引用,所以结果为true。


2
@OP 只是补充一下,你应该始终使用 String.Equals 来比较字符串。 - Mataniko
10
不,你只需要确保如果使用operator ==,则变量是编译时字符串类型即可。仅在一个或多个对象未静态地类型化为string时使用string.Equals(这应该非常罕见)。 - Servy
1
@Servy 更常见的使用 string.equals 的情况是当您想要使用不同的比较系统时。我经常使用 OrdinalOrdinalIgnoreCase,特别是因为它们比标准的 == 快得多。 - Destrictor

19

这里有两件重要的事情:

首先,表达式"string" + 1在运行时评估,而"string" + "1"在编译时评估。

其次,您正在使用引用比较。运行时生成的字符串实际上引用不同的对象,而编译时生成的字符串引用相同的对象,因此第一个表达式为false,第二个表达式为true

如果您感兴趣,生成的IL代码如下:

// bool a1 = (object)("string" + 1) == ("string" + 1);
// bool a2 = (object)("string" + "1") == ("string" + "1");

IL_0000:  ldstr       "string"
IL_0005:  ldc.i4.1    
IL_0006:  box         System.Int32
IL_000B:  call        System.String.Concat
IL_0010:  ldstr       "string"
IL_0015:  ldc.i4.1    
IL_0016:  box         System.Int32
IL_001B:  call        System.String.Concat
IL_0020:  ceq         
IL_0022:  stloc.0     // a1
IL_0023:  ldstr       "string1"
IL_0028:  ldstr       "string1"
IL_002D:  ceq         
IL_002F:  stloc.1     // a2

整洁。能否提及如何查看这样的中间语言(IL)? - kenchilada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接