==和Equals()之间的c#差异

我在silverlight应用程序中有一个条件,比较2个字符串,由于某种原因,当我使用==时,它返回,而.Equals()返回真正的

代码如下:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}


if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}

你知道为什么会这样吗?

397439 次浏览

当在object类型的表达式上使用==时,它将解析为System.Object.ReferenceEquals

Equals只是一个virtual方法,它的行为就是这样,所以将使用覆盖的版本(对于string类型,它比较内容)。

当比较对象引用和字符串时(即使对象引用引用了字符串),特定于字符串类的==操作符的特殊行为将被忽略。

正常情况下(当不处理字符串时),Equals比较,而==比较对象引用。 如果您正在比较的两个对象都引用了一个对象的相同实例,那么两个对象都将返回true,但如果其中一个具有相同的内容并且来自不同的来源(是具有相同数据的独立实例),则只有Equals将返回true。然而,正如注释中所指出的,string是一个特殊情况,因为它覆盖了==操作符,因此在纯处理字符串引用(而不是对象引用)时,即使它们是单独的实例,也只比较值。下面的代码说明了行为的细微差别:

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,而忽略了实现操作符==。这意味着.Equals将实际测量值的相等性,而==将测量它们是否是相同的引用。

当我处理一个定义不断变化的新类型或编写泛型算法时,我发现最佳实践如下

  • 如果我想在c#中比较引用,我直接使用Object.ReferenceEquals(在通用情况下不需要)
  • 如果我想比较值,我使用EqualityComparer<T>.Default

在某些情况下,当我觉得==的使用是不明确的,我将显式地使用Object.Reference =在代码中消除不明确。

Eric Lippert最近写了一篇博文,主题是为什么在CLR中有两种相等的方法。值得一读

我有点糊涂了。如果Content的运行时类型是字符串类型,则==和Equals都应返回true。然而,由于这似乎不是这样的情况下,然后运行时类型的内容不是字符串和调用它的Equals是做一个参考平等,这解释了为什么Equals(“能量攻击”)失败。然而,在第二种情况下,关于应该调用哪个重载的==静态操作符的决定是在编译时做出的,这个决定似乎是==(string,string)。这提示我,内容提供了一个隐式转换到字符串。

我想补充的是,如果你将对象转换为字符串,那么它将正确工作。这就是为什么编译器会给你一个警告说:

可能是无意的参考比较;为了进行价值比较, 转换左边的类型为'string'

给答案再加一分。

.EqualsTo()方法提供了比较区域性和区分大小写的方法。

= =操作符

  1. 如果操作数为值类型并且它们的相等,则返回true否则返回false。
  2. 如果操作数是引用类型 (string除外),并且都指向同一个实例(同一对象),则返回true否则返回false。
  3. 如果操作数类型为字符串且它们的相等,则返回true否则返回false。

.Equals

  1. 如果操作数为引用类型,则执行参考平等,即如果两个操作数都指向同一个实例(同一对象),则返回true否则返回false。
  2. 如果操作数是值类型,那么不像==运算符,它首先检查它们的类型,如果它们的类型相同,它执行==运算符,否则返回false。

首先,有一个区别。对数字的

> 2 == 2.0
True


> 2.Equals(2.0)
False

对于字符串

> string x = null;
> x == null
True


> x.Equals(null)
NullReferenceException

在这两种情况下,==.Equals更有用

c#中的==令牌用于两个不同的相等检查操作符。当编译器遇到该令牌时,它将检查正在比较的类型是否为正在比较的特定组合类型(*)或两个类型都可以转换为的类型组合实现了相等运算符重载。如果编译器发现这样的重载,就会使用它。否则,如果这两个类型都是引用类型,并且它们不是不相关的类(可能是接口,也可能是相关的类),编译器将把==视为引用比较操作符。如果两个条件都不适用,编译将失败。

请注意,其他一些语言为两个相等检查操作符使用单独的令牌。在VB。例如,=令牌在表达式中仅用于可重载的相等检查操作符,而Is则用作引用测试或空测试操作符。在没有覆盖相等检查操作符的类型上使用=将会失败,试图将Is用于测试引用是否相等或为空以外的任何目的也会失败。

(*)类型通常只重载相等操作符以便与自身进行比较,但对于类型来说重载相等操作符以便与其他特定类型进行比较可能是有用的;例如,int可以定义一个相等运算符来与float进行比较,这样16777217就不会报告自己等于16777216f。事实上,由于没有定义这样的操作符,c#将把int提升到float,在相等检查操作符看到它之前舍入到16777216f;然后,该操作符看到两个相等的浮点数,并将它们报告为相等,而不知道发生了舍入运算。

当我们创建任何对象时,对象有两部分,一部分是内容,另一部分是对该内容的引用。 ==比较内容和引用; equals()只比较内容

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq

< em > = = < / em >

==操作符可用于比较任何类型的两个变量,而它只是比较比特

int a = 3;
byte b = 3;
if (a == b) { // true }

注意:在int的左边有更多的0,但我们在这里不关心它。

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为false

a和c的位模式是相同的,所以使用==它们是相等的。

< em > = (): < / em >

使用equals()方法查看如果两个不同的对象相等

例如两个不同的String对象都表示“Jane”中的字符

Equal和==之间的唯一区别是对象类型比较。在其他情况下,例如引用类型和值类型,它们几乎是相同的(要么都是位相等,要么都是引用相等)。

< p >对象: Equals:位的相等 ==:引用相等

string:(equals和==对于字符串是相同的,但如果字符串中的一个被更改为object,那么比较结果将不同) Equals:位的相等 ==:按位相等

参见在这里获得更多解释。

@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

非常棒的答案和例子!

我想补充一下两者之间的根本区别,

==这样的操作符不是多态的,而Equals

记住这个概念,如果你算出任何例子(通过查看左手和右手引用类型,并检查/知道类型是否确实重载了==操作符和重写了Equals),你肯定会得到正确的答案。

据我所知,答案很简单:

  1. ==比较对象引用。
  2. .Equals比较对象内容。
  3. String数据类型总是像内容比较一样。

我希望我是对的,这回答了你的问题。

因为到目前为止还没有提到.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并不完全相同,所以可以使用静态字符串。=方法。这样,如果两边不是相同的类型,您仍然可以比较内容,如果其中一方为空,则可以避免异常。

   bool areEqual = String.Equals("Somestring", MyString);

写起来有点麻烦,但在我看来,使用起来更安全。

以下是从微软复制的一些信息:

public static bool Equals (string a, string b);

参数

# EYZ0字符串

要比较的第一个字符串,或null

# EYZ0字符串

要比较的第二个字符串,或null

返回# EYZ0

如果a的值与b的值相同,则返回true;否则,# EYZ3。如果ab都是null,则该方法返回true

作为对已经很好的答案的补充:这种行为不仅限于字符串或比较不同的数字类型。即使两个元素的类型对象都是相同的基础类型。“==”不行。

下面的屏幕截图显示了比较两个object {int} -值的结果

Example From VS2017 .

注意,在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。

这是由于值相等(equal方法)和引用相等(==运算符),因为equal方法检查值,而相同的==检查引用。

==运算符覆盖在https://referencesource.microsoft.com/上的字符串类中可用的代码

现在更容易理解了,equal方法也有两个实现一个来自string类本身,一个来自object类。它对性能的影响以及我也运行一些基本的代码,并试图理解基准测试。

我分享下面的结果,如果我错了,请纠正或建议。有3种情况,我对所有情况运行了相同的代码,这就是结果。

这里我使用的是字符串。相等的方法比较两个字符串和两个字符串有相同的值。string.equals (a, b)

第一次运行:5608195 tick

第二次运行:5529387个刻度

第三次运行:5622569滴答

总蜱数:16760151

这里我使用的是字符串。Equal()方法(重载的一个)用于比较两个字符串,并且两个字符串具有相同的值。 a.equals (b) < / p >

第一次运行:6738583滴答

第二轮:6452927

第三轮:7168897个刻度

总蜱虫= 20360407

案例3:这里我使用==操作符比较2个字符串,两个字符串都有相同的值。 = = b < / p >

第一次运行:6652151滴答

第二次运行:7514300个tick

第三轮: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++;
}
}
}

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()工作正常,但==永远不会工作。

此外,虽然我让它们具有相同的行为,但仍然有一个区别:哪个==函数将被调用取决于左边的值:

        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