如何在 C# 中正确比较字符串:Equalsor ==?
string str1 = "s";
string str2 = "s";
Console.WriteLine("eq: " + str1.Equals(str2));
Console.WriteLine("==: " + (str1 == str2));
在这两种情况下,结果True都是尽管String是一个类并且运算符==必须比较引用。
IlDasm表明根据方法创建并比较了 2 个变量Equals,== (op_Equality)
IL_0000: nop
IL_0001: ldstr "s"
IL_0006: stloc.0
IL_0007: ldstr "s"
IL_000c: stloc.1
IL_000d: ldstr "eq: "
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: callvirt instance bool [mscorlib]System.String::Equals(string)
IL_0019: box [mscorlib]System.Boolean
IL_001e: call string [mscorlib]System.String::Concat(object, object)
IL_0023: call void [mscorlib]System.Console::WriteLine(string)
IL_0028: nop
IL_0029: ldstr "==: "
IL_002e: ldloc.0
IL_002f: ldloc.1
IL_0030: call bool [mscorlib]System.String::op_Equality(string, string)
IL_0035: box [mscorlib]System.Boolean
IL_003a: call string [mscorlib]System.String::Concat(object, object)
==在 C# 中,通过, 和比较字符串是正确的Equals。但是比较使用==.这是为什么?
该方法
Equals涉及比较引用类型对象的值,它被声明virtual为字符串,它被重载并按预期按值比较它们。在您的课程中,您必须为其提供自己的实现。否则,它的行为将与ReferenceEquals指向多个对象的引用一样false,即使它们的值相等。字符串运算符
==提供了自己的实现,不同于所有其他引用类型对象的标准。如果被比较的引用是 typeSystem.String,那么它会先比较这两个引用是否指向同一个对象,如果不是,它会比较这两个 type 的引用的System.String值。但需要注意一点,如果我们比较一个
System.String(string) 类型的对象和一个System.Object指向字符串的 ( object ) 类型的对象,它们将按值进行比较。例子:
result将等于true,因为它将obj被强制转换为 typestring,因为Equals我们在字符串( type 的对象)上调用了该方法string。但是如果我们比较一个
System.Object指向字符串的类型(object)对象和一个System.String( )类型的对象string,它们将通过引用进行比较。例子:
result将等于false,因为它将str被转换为 typeobject,因为Equals我们在 type 的对象上调用了该方法object。因此,在这种情况下,
object转换为类型很重要string操作员
==不需要仅比较引用。在 C# 中,运算符是可以被重写的,而且对于很多类型来说它自然被重写了。引用比较只是
==未覆盖运算符的类型的默认行为。对于运算符被重新定义的类型,
==并且很可能会被重新定义Equals,两种比较方法的结果很可能是相同的(如果不是,那么它的作者只是在设计类型时犯了一个错误)。这是来自参考源
==的 String的实现:这里是非静态 Equals 的实现:
它们的不同之处仅在于对非静态性的小修正。两者都比较引用并检查大小写
null != null,然后比较不平等的长度,然后才比较值。在 C# 中,== 运算符和 Equals 方法都为字符串重载,因为字符串通常需要按值而不是按引用进行比较。在 == 运算符的情况下,首先比较字符串指针,如果它们相等,则该方法返回 true。否则,将检查空操作数(如果其中至少有一个为空,则返回 false)。然后比较字符串长度。然后是字符串逐个字符的比较(即按值比较)。这是在本机代码中使用指针完成的(显然是出于性能原因),并且还使用了循环展开(显然是出于相同的原因,但在这种情况下这些细节并不重要)。如果你对细节感兴趣,你可以看这里