![](/img/trans.png)
[英]What is the difference between == and Equals() for primitives in C#?
[英]C# difference between == and Equals()
我在比较 2 个字符串的 silverlight 应用程序中有一个条件,由于某种原因,当我使用==
时它返回false而.Equals()
返回true 。
这是代码:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
为什么会发生这种情况?
当==
用于object
类型的表达式时,它将解析为System.Object.ReferenceEquals
。
Equals
只是一个virtual
方法并且行为如此,因此将使用覆盖的版本(对于string
类型比较内容)。
将对象引用与字符串进行比较时(即使对象引用引用字符串),特定于字符串类的==
运算符的特殊行为将被忽略。
通常(即不处理字符串时), Equals
比较值,而==
比较对象引用。 如果您比较的两个对象指的是一个对象的同一个实例,则两者都将返回 true,但如果一个具有相同的内容并且来自不同的源(是具有相同数据的单独实例),则只有 Equals返回真。 但是,正如注释中所指出的,字符串是一种特殊情况,因为它覆盖了==
运算符,因此在纯粹处理字符串引用(而不是对象引用)时,即使它们是单独的实例,也只会比较值。 以下代码说明了行为的细微差别:
string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine($"{object.ReferenceEquals(s1, s2)} {s1 == s2} {s1.Equals(s2)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s3)} {s1 == s3} {s1.Equals(s3)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s4)} {s1 == s4} {s1.Equals(s4)}");
输出是:
True True True
False True True
False False True
==
和.Equals
都取决于实际类型中定义的行为和调用站点的实际类型。 两者都只是方法/运算符,可以在任何类型上覆盖并给出作者想要的任何行为。 根据我的经验,我发现人们在对象上实现.Equals
而忽略实现 operator ==
是很常见的。 这意味着.Equals
将实际测量值的相等性,而==
将测量它们是否是相同的引用。
当我使用定义不断变化的新类型或编写泛型算法时,我发现最佳实践如下
Object.ReferenceEquals
(一般情况下不需要)EqualityComparer<T>.Default
在某些情况下,当我觉得==
的用法有歧义时,我会在代码中明确使用Object.Reference
equals 来消除歧义。
Eric Lippert 最近发表了一篇关于为什么 CLR 中有 2 种相等方法的主题的博客文章。 值得一读
据我了解,答案很简单:
==
比较对象引用。.Equals
比较对象内容。String
数据类型总是像内容比较一样。我希望我是正确的,它回答了你的问题。
首先,是有区别的。 对于数字
> 2 == 2.0
True
> 2.Equals(2.0)
False
而对于字符串
> string x = null;
> x == null
True
> x.Equals(null)
NullReferenceException
在这两种情况下, ==
比.Equals
我要补充一点,如果您将对象转换为字符串,那么它将正常工作。 这就是为什么编译器会给你一个警告说:
可能的意外参考比较; 要进行值比较,请将左侧强制转换为“字符串”
因为到目前为止还没有提到.Equal
方法的静态版本,我想在这里添加这个来总结和比较 3 个变体。
MyString.Equals("Somestring")) //Method 1
MyString == "Somestring" //Method 2
String.Equals("Somestring", MyString); //Method 3 (static String.Equals method) - better
其中MyString
是来自代码中其他地方的变量。
背景信息和总结:
在 Java 中,不应使用==
来比较字符串。 如果您需要同时使用这两种语言,我会提到这一点,并且让您知道使用==
也可以用 C# 中更好的东西代替。
在 C# 中,使用方法 1 或方法 2 比较字符串没有实际区别,只要它们都是字符串类型。 但是,如果一个为空,一个是另一种类型(如整数),或者一个表示具有不同引用的对象,那么,如最初的问题所示,您可能会遇到比较内容是否相等可能不会返回什么你期待。
建议的解决方案:
因为在比较事物时使用==
与使用.Equals
并不完全相同,所以您可以改用静态 String.Equals方法。 这样,如果两侧的类型不同,您仍然会比较内容,如果一个为空,您将避免异常。
bool areEqual = String.Equals("Somestring", MyString);
写的多一点,但在我看来,使用起来更安全。
以下是从 Microsoft 复制的一些信息:
public static bool Equals (string a, string b);
参数
a
字符串
要比较的第一个字符串,或null
。
b
字符串
要比较的第二个字符串,或null
。
返回Boolean
如果a
的值与b
的值相同,则为true
; 否则为false
。 如果a
和b
都为null
,则该方法返回true
。
给答案补充一点。
.EqualsTo()
方法为您提供了与文化和区分大小写进行比较的条件。
@BlueMonkMN 的早期答案还有另一个维度。 额外的维度是,@Drahcir 标题问题的答案也取决于我们如何获得string
值。 为了显示:
string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("\n Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));
Console.WriteLine("\n Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));
输出是:
True True True
Case1 - A method changes the value:
False True True
False False True
Case2 - Having only literals allows to arrive at a literal:
True True True
True True True
我在这里有点困惑。 如果 Content 的运行时类型是字符串类型,则 == 和 Equals 都应返回 true。 但是,由于情况似乎并非如此,因此内容的运行时类型不是字符串,并且对其调用 Equals 是在执行引用相等,这解释了 Equals("Energy Attack") 失败的原因。 然而,在第二种情况下,关于应该调用哪个重载 == 静态运算符的决定是在编译时做出的,这个决定似乎是 ==(string,string)。 这向我表明 Content 提供了到字符串的隐式转换。
真的很棒的答案和例子!
我只想补充两者之间的根本区别,
==
等运算符不是多态的,而Equals
是多态的
考虑到这个概念,如果您计算出任何示例(通过查看左手和右手引用类型,并检查/知道该类型是否实际具有 == 运算符重载和 Equals 被覆盖),您一定会得到正确的答案.
这是由于值相等(相等方法)和引用相等(== 运算符),因为相等方法检查值,而相同的 == 检查引用。
== 运算符覆盖代码在https://referencesource.microsoft.com/上的字符串类中可用
所以现在更容易理解了,equal 方法也有 2 个实现,一个来自字符串类本身,一个来自对象类。 它对性能的影响以及我还运行了一些基本代码并尝试了解基准测试。
我在下面分享结果请纠正或建议我是否在某处错了。 有 3 个案例,我为所有案例运行了相同的代码,这就是结果。
案例 1:这里我使用的是字符串。 用于比较 2 个字符串且两个字符串具有相同值的 equal 方法。 string.equals(a,b)
第一次运行:5608195 滴答
第二次运行:5529387 滴答
第三次运行:5622569 滴答声
总滴答数:16760151
情况 2:这里我使用的是字符串。 用于比较 2 个字符串并且两个字符串具有相同值的 equal() 方法(重载一个)。 a.等于(b)
第一次运行:6738583 个滴答声
第二次运行:6452927 个滴答声
第三次运行:7168897 个滴答声
总滴答数=20360407
情况 3:这里我使用 == 运算符来比较 2 个字符串,并且两个字符串都具有相同的值。 a==b
第一次运行:6652151 个滴答声
第二次运行:7514300 滴答
第三次运行:7634606 滴答
总滴答数=21801057
class Program
{
private static int count;
static string a = "abcdef";
static string b = "abcdef";
static void Main(string[] args)
{
for (int j = 1; j <= 3; j++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 1; i <= 1000; i++)
{
checkString();
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
}
Console.ReadLine();
}
public static void checkString()
{
for (int i = 1; i <= 100000; i++)
{
if (a==b)
count++;
}
}
}
C# 中的==
标记用于两个不同的相等检查运算符。 当编译器遇到该标记时,它将检查被比较的任一类型是否已为被比较的特定组合类型 (*) 或两种类型都可以转换为的类型组合实现了相等运算符重载。 如果编译器发现这样的重载,它将使用它。 否则,如果这两种类型都是引用类型并且它们不是不相关的类(可能是接口,也可能是相关类),编译器会将==
视为引用比较运算符。 如果两个条件都不适用,编译将失败。
请注意,其他一些语言对两个相等检查运算符使用单独的标记。 例如,在 VB.NET 中, =
标记在表达式中仅用于可重载的相等检查运算符,而Is
用作引用测试或空测试运算符。 在不覆盖相等检查运算符的类型上使用=
将失败,尝试将Is
用于测试引用相等性或无效性以外的任何目的也会失败。
(*) 类型通常只重载相等以与自身进行比较,但对于类型来说,重载相等运算符以与其他特定类型进行比较可能很有用; 例如, int
可以(恕我直言应该有但没有)定义了一个相等的运算符来与float
进行比较,这样 16777217 就不会报告自己等于 16777216f。 实际上,由于没有定义这样的运算符,C# 会将int
提升为float
,在相等检查运算符看到它之前将其四舍五入为 16777216f ; 该运算符然后看到两个相等的浮点数并将它们报告为相等,不知道发生的舍入。
Equals()
和==
是否相同取决于实现。 因为 C# 允许用户分别为Equals()
和==
设置不同的行为。
class CompareTest
{
public readonly int val;
public CompareTest(int val)
{
this.val = val;
}
public override bool Equals(object obj)
{
return obj is CompareTest test && this.val == test.val;
}
public override int GetHashCode()
{
return val;
}
public static bool operator == (CompareTest a, object b)
{
return Equals(a, b);
}
public static bool operator != (CompareTest a, object b)
{
return !(a == b);
}
}
在此示例中,我使Equals()
和==
具有相同的行为。 但是如果我让它们不同呢? 例如:
public static bool operator == (CompareTest a, object b)
{
return false;
}
Equals()
正常工作,但==
永远不会工作。
此外,虽然我使它们具有相同的行为,但仍有一个区别:将调用哪个==
function 取决于左侧的值:
Compare Test a = new CompareTest(1);
object b = new CompareTest(1);
CompareTest c = new CompareTest(1);
Debug.Log("AB " + (a == b)); // true
Debug.Log("BA " + (b == a)); // false! because it calls object's == function
Debug.Log("AC " + (a == c)); // true
Debug.Log("CA " + (c == a)); // true
当我们创建任何对象时,对象有两个部分,一个是内容,另一个是对该内容的引用。 ==
比较内容和参考; equals()
只比较内容
http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
请注意,C# 中有两种不同类型的相等性
1- Value Equality
(对于 int、DateTime 和 struct 等值类型)
2- Reference Equality
(对于对象)
有两种基本的标准协议用于实现相等性检查。
1- ==
和!=
运算符。
2- virtual
Equals
方法。
== 和 != 是静态解析的,这意味着 C# 将在编译时决定哪种类型将执行比较。
例如value-type
int x = 50;
int y = 50;
Console.WriteLine (x == y); // True
但对于reference type
object x = 50;
object y = 50;
Console.WriteLine (x == y); // False
Equals()
最初在运行时根据操作数的实际类型进行解析。
例如,在以下示例中,在运行时,将决定Equals()
将应用于 int 值,结果为true
。
object x = 5;
object y = 5;
Console.WriteLine (x.Equals (y)); // True
但是,对于引用类型,它将使用引用相等性检查。
MyObject x = new MyObject();
MyObject y = x;
Console.WriteLine (x.Equals (y)); // True
请注意, Equals()
对struct
使用结构比较,这意味着它在结构的每个字段上调用 Equals。
==
== 运算符可用于比较任何类型的两个变量,它只是比较位。
int a = 3;
byte b = 3;
if (a == b) { // true }
注意:int 的左侧有更多的零,但我们在这里不关心。
int a (00000011) == 字节 b (00000011)
记住 == 运算符只关心变量中位的模式。
使用 == 如果两个引用(原语)指向堆上的同一个对象。
无论变量是引用还是原始变量,规则都是相同的。
Foo a = new Foo();
Foo b = new Foo();
Foo c = a;
if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }
a == c 为真 a == b 为假
a 和 c 的位模式相同,因此使用 == 时它们相等。
平等的():
使用 equals() 方法查看两个不同的对象是否相等。
例如两个不同的 String 对象,它们都代表“Jane”中的字符
Equal 和 == 之间的唯一区别在于对象类型比较。 在其他情况下,例如引用类型和值类型,它们几乎相同(要么都是按位相等,要么都是引用相等)。
object: Equals: 按位相等 ==: 引用相等
字符串:(字符串的equals和==是一样的,但是如果字符串中的一个变成了对象,那么比较结果就会不同) Equals: bit-wisequality == : bit-wisequality
有关更多解释,请参见此处。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.