关于.NET:==和equals()之间的差异

C# difference between == and Equals()

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

代码如下:

1
2
3
4
5
6
7
8
9
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将返回true。但是,正如注释中所指出的,字符串是一种特殊情况,因为它会重写==运算符,这样,在纯处理字符串引用(而不是对象引用)时,即使这些值是单独的实例,也只会比较这些值。下面的代码说明了行为上的细微差别:

1
2
3
4
5
6
7
string s1 ="test";
string s2 ="test";
string s3 ="test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
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));

输出是:

1
2
3
True True True
False True True
False False True


==.Equals都取决于实际类型和调用站点的实际类型中定义的行为。这两者都只是方法/运算符,可以在任何类型上被重写,并给出作者希望的任何行为。根据我的经验,人们在一个对象上执行.Equals,但忽略了执行操作符==,这是很常见的。这意味着.Equals将实际测量值的相等性,而==将测量值是否相同。

当我使用一个定义为flux或编写通用算法的新类型时,我发现最佳实践如下

  • 如果我想比较c中的引用,我直接使用Object.ReferenceEquals(一般情况下不需要)
  • 如果我想比较值,我使用EqualityComparer.Default

在某些情况下,当我觉得==的用法不明确时,我会在代码中显式地使用Object.Referenceequals来消除歧义。

埃里克·利珀特最近发表了一篇关于为什么在CLR中存在两种平等方法的博客文章。值得一读

  • http://blogs.msdn.com/ericlippet/archive/2009/04/09/double-your-dispatch-double-your-fun.aspx


首先,这是有区别的。对于数字

1
2
3
4
5
> 2 == 2.0
True

> 2.Equals(2.0)
False

弦乐

1
2
3
4
5
6
> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

在这两种情况下,==的行为比.Equals更有用。


我还要补充一点,如果您将对象强制转换为字符串,那么它将正常工作。这就是为什么编译器会警告您说:

Possible unintended reference comparison; to get a value comparison,
cast the left hand side to type 'string'


==算符1。如果操作数是值类型且其值相等,则返回true或false。2。如果操作数是引用类型(字符串除外),并且两者都引用同一对象,则返回true或false。三。如果操作数是字符串类型且其值相等,则返回true或false。

等于1。如果操作数是引用类型,则执行引用相等(即如果两个操作数都引用同一对象,则返回true或false)。2。如果操作数是值类型,则与==运算符不同,它首先检查其类型,如果它们的类型相同,则执行==运算符,否则返回false。


据我所知,答案很简单:

  • ==比较对象引用。
  • .equals比较对象内容。
  • 字符串数据类型总是起到内容比较的作用。
  • 我希望我是对的,它回答了你的问题。


    因为到目前为止还没有提到.Equal方法的静态版本,所以我想在这里添加这个内容来总结和比较这3种变体。

    1
    2
    3
    MyString.Equals("Somestring"))          //Method 1
    MyString =="Somestring"                //Method 2
    String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

    其中MyString是来自代码中其他地方的变量。

    背景信息和摘要:

    在使用EDCOX1的Java中,不应该使用2个比较字符串。我提到这个,以防你需要同时使用两种语言和让你知道使用==也可以用C语言中更好的东西来代替。

    在C中,使用方法1或方法2比较字符串没有实际区别,只要两者都是字符串类型。但是,如果一个为空,一个为另一种类型(如整数),或者一个表示具有不同引用的对象,那么,正如最初的问题所显示的那样,您可能会体验到将内容与相等项进行比较可能不会返回您期望的结果。

    建议的解决方案:

    因为使用==与使用.Equals不完全相同,所以可以使用静态string.equals方法。这样,如果两侧的类型不同,您仍然可以比较内容,如果其中一个为空,则可以避免异常。

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

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

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

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

    参数

    a

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

    b

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

    返回Boolean

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


    在答案中再加一个点。

    .EqualsTo()方法提供了与文化和区分大小写进行比较的方法。


    @bluemonkmn之前的答案还有另一个维度。另外一个维度是@drahcir标题问题的答案,如所述,也取决于我们如何得出string值。举例说明:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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("
      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("
      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));

    输出是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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

    我有点困惑。如果内容的运行时类型为string类型,则==和等于都应返回true。但是,由于看起来不是这样,所以运行时内容类型不是字符串,调用equals是在进行引用相等,这解释了equals("能量攻击")失败的原因。但是,在第二种情况下,应该调用overloaded==static运算符的决定是在编译时作出的,而这个决定似乎是==(string,string)。这向我建议内容提供到字符串的隐式转换。


    非常好的答案和例子!

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

    Operators such as == are not polymorphic, while Equals is

    考虑到这个概念,如果您想出任何例子(通过查看左侧和右侧的引用类型,并检查/知道该类型是否实际具有==运算符重载和等于被重写),您一定会得到正确的答案。


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

    注意,其他一些语言对这两个相等性检查操作符使用单独的标记。例如,在vb.net中,=标记仅用于表达式中的可重载相等检查运算符,Is用作引用测试或空测试运算符。在不重写相等检查运算符的类型上使用=的操作将失败,而试图将Is用于除测试引用相等或无效之外的任何目的的操作也将失败。

    (*)类型通常只重载相等以便与自身进行比较,但对于类型来说,重载相等运算符以便与其他特定类型进行比较可能很有用;例如,int可以(imho应该但不应该)定义相等运算符以便与float进行比较,这样16777217就不会端口本身等于16777216F。实际上,由于没有定义此类运算符,C会将int提升到float,在相等检查运算符看到之前将其四舍五入到16777216F;然后,该运算符看到两个相等的浮点数并将其报告为相等,而不知道发生了四舍五入。


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

    http://www.codeproject.com/articles/584128/what-is-the-difference-between-equalsequals-and-eq


    =

    ==运算符可用于比较任何类型的两个变量,它只比较位。

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

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

    int a(00000011)==字节b(00000011)

    记住==运算符只关心变量中位的模式。

    如果两个引用(原语)引用堆上的同一对象,则使用==

    无论变量是引用还是原语,规则都是相同的。

    1
    2
    3
    4
    5
    6
    7
    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()方法查看两个不同的对象是否相等。

    例如,两个不同的字符串对象都表示"jane"中的字符


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

    对象:等于:位智能相等==:参考等式

    string:(对于string,equals和==相同,但如果其中一个字符串更改为object,则比较结果将不同)等于:位智能相等==:位相等

    请参阅此处了解更多说明。