这个问题在这里已有答案:
我最近被介绍到一个大型代码库,并注意到所有字符串比较都是使用String.Equals()
而不是==
完成的。
你觉得这是什么原因?
很可能很大一部分开发人员来自Java背景,使用==
比较字符串是错误的,不起作用。
在C#中,只要它们被键入为字符串,就没有(实际)差异(对于字符串)。
如果他们输入object
或T
然后在这里看到其他答案,谈论泛型方法或运算符重载,你肯定想使用Equals方法。
string.Equals
和==
之间存在实际差异
bool result = false;
object obj = "String";
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;
// Comparision between object obj and string str2 -- Com 1
result = string.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true
// Comparision between object obj and string str3 -- Com 2
result = string.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false
// Comparision between object obj and string str4 -- Com 3
result = string.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true
// Comparision between string str2 and string str3 -- Com 4
result = string.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true
// Comparision between string str2 and string str4 -- Com 5
result = string.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true
// Comparision between string str3 and string str4 -- Com 6
result = string.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true
// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false
添加手表
obj "String" {1#} object {string}
str2 "String" {1#} string
str3 "String" {5#} string
str4 "String" {1#} string
obj2 "String" {5#} object {string}
现在看看{1#}
和{5#}
obj
,str2
,str4
和obj2
的引用是相同的。
obj
和obj2
是object type
,其他人是string type
object
和string
,以便执行引用相等性检查
obj和str2指向相同的引用,因此结果为真object
和string
,以便执行引用相等性检查
obj和str3指向不同的引用,因此结果为falseobject
和string
,以便执行引用相等性检查
obj和str4指向相同的引用,因此结果为真string
和string
,以便执行字符串值检查
str2和str3都是“String”,因此结果为truestring
和string
,以便执行字符串值检查
str2和str4都是“String”,因此结果为truestring
和string
,以便执行字符串值检查
str3和str4都是“String”,因此结果为trueobject
和object
以执行引用相等性检查 - obj和obj2指向不同的引用,因此结果为false==和String.Equals方法之间有一个微妙但非常重要的区别:
class Program
{
static void Main(string[] args)
{
CheckEquality("a", "a");
Console.WriteLine("----------");
CheckEquality("a", "ba".Substring(1));
}
static void CheckEquality<T>(T value1, T value2) where T : class
{
Console.WriteLine("value1: {0}", value1);
Console.WriteLine("value2: {0}", value2);
Console.WriteLine("value1 == value2: {0}", value1 == value2);
Console.WriteLine("value1.Equals(value2): {0}", value1.Equals(value2));
if (typeof(T).IsEquivalentTo(typeof(string)))
{
string string1 = (string)(object)value1;
string string2 = (string)(object)value2;
Console.WriteLine("string1 == string2: {0}", string1 == string2);
}
}
}
生成此输出:
value1: a value2: a value1 == value2: True value1.Equals(value2): True string1 == string2: True ---------- value1: a value2: a value1 == value2: False value1.Equals(value2): True string1 == string2: True
您可以看到==运算符返回false为两个明显相等的字符串。为什么?因为泛型方法中使用的==运算符被解析为System.Object定义的op_equal方法(方法在编译时具有的唯一保证),这意味着它是引用相等而不是值相等。
如果有两个值显式地键入System.String,则==具有值 - 相等语义,因为编译器将==解析为System.String.op_equal而不是System.Object.op_equal。
所以为了安全起见,我几乎总是使用String.Equals代替我总是得到我想要的值相等语义。
如果其中一个值为null,为了避免NullReferenceExceptions,我总是使用静态String.Equals方法:
bool true = String.Equals("a", "ba".Substring(1));
String.Equals
确实提供过载来处理套管和文化意识的比较。如果您的代码没有使用这些代码,那么开发人员可能只会习惯使用Java,其中(如Matthew所说),您必须使用.Equals方法进行内容比较。
两种方法在功能上都是相同的 - 它们比较值。 正如MSDN上所写:
String.Equals
方法 - 确定此实例和另一个指定的String对象是否具有相同的值。 (http://msdn.microsoft.com/en-us/library/858x0yyx.aspx)==
- 虽然string是引用类型,但是定义了相等运算符(==
和!=
)来比较字符串对象的值,而不是引用。这使得对字符串相等性的测试更加直观。 (http://msdn.microsoft.com/en-en/library/362314fe.aspx)但是,如果您的一个字符串实例为null,则这些方法的工作方式不同:
string x = null;
string y = "qq";
if (x == y) // returns false
MessageBox.Show("true");
else
MessageBox.Show("false");
if (x.Equals(y)) // returns System.NullReferenceException: Object reference not set to an instance of an object. - because x is null !!!
MessageBox.Show("true");
else
MessageBox.Show("false");
有一些关于this article的文章你可能会觉得很有意思,Jon Skeet引用了一些文章。似乎使用几乎是一样的。
Jon Skeet表示,当字符串很短时,实例Equals“的性能会稍好一些 - 随着字符串长度的增加,这种差异变得完全无关紧要。”
我想补充说还有另一个不同之处。这与安德鲁发布的内容有关。
它也与在我们的软件中发现错误非常烦人有关。请参阅以下简化示例(我也省略了空检查)。
public const int SPECIAL_NUMBER = 213;
public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}
这将编译并始终返回false
。虽然以下将给出编译错误:
public const int SPECIAL_NUMBER = 213;
public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
return (numberTextBoxTextValue == SPECIAL_NUMBER);
}
我们必须解决一个类似的问题,有人使用Equals
比较不同类型的枚举。在意识到它是导致错误的原因之前,您将阅读这么多次。特别是如果SPECIAL_NUMBER
的定义不在问题区域附近。
这就是为什么我真的反对在没有必要的情况下使用Equals。你失去了一点类型安全性。
我一直在试图解决一个错误,因为我读了这个页面并得出结论,在实践中没有任何有意义的差异,所以我会在这里发布此链接以防其他人发现他们得到不同的结果超出==和等于。
Object == equality fails, but .Equals succeeds. Does this make sense?
string a = "x";
string b = new String(new []{'x'});
Console.WriteLine("x == x " + (a == b));//True
Console.WriteLine("object x == x " + ((object)a == (object)b));//False
Console.WriteLine("x equals x " + (a.Equals(b)));//True
Console.WriteLine("object x equals x " + (((object)a).Equals((object)b)));//True