C#==和等于()之间的差

C#==和等于()之间的差,c#,.net,equals,C#,.net,Equals,我在silverlight应用程序中有一个比较两个字符串的条件,出于某种原因,当我使用=时,它返回false,而.Equals()返回true int a = 3; byte b = 3; if (a == b) { // true } 代码如下: if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack")) { // Execute code } if (((ListBoxItem)lstB

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

int a = 3;
byte b = 3;
if (a == b) { // true }
代码如下:

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

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

关于发生这种情况的原因是什么?

==
用于
对象类型的表达式时,它将解析为


只是一个
virtual
方法,其行为也是如此,因此将使用重写版本(对于
string
类型,该版本比较内容)。

将对象引用与字符串进行比较时(即使对象引用引用的是字符串),特定于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
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
是很常见的,但却忽略了实现操作符
=
。这意味着
.Equals
将实际测量值的相等性,而
=
将测量它们是否是相同的引用

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

  • 如果我想比较C#中的引用,我直接使用
    Object.ReferenceEquals
    (在一般情况下不需要)
  • 如果要比较值,请使用
    EqualityComparer.Default
在某些情况下,当我觉得
==
的用法模棱两可时,我会在代码中显式使用
Object.Reference
equals来消除模棱两可之处

Eric Lippert最近发表了一篇博客文章,主题是为什么CLR中有两种平等方法。值得一读


    • 我在这里有点困惑。如果内容的运行时类型为string类型,则==和Equals都应返回true。然而,由于情况似乎并非如此,因此内容的运行时类型不是字符串,对其调用Equals就是执行引用相等,这解释了Equals(“能量攻击”)失败的原因。然而,在第二种情况下,关于应该调用哪个重载==静态运算符的决定是在编译时做出的,并且这个决定似乎是==(string,string)。这对我来说意味着内容提供了对字符串的隐式转换。

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

      可能的非预期参考比较;要进行价值比较, 将左侧强制转换为键入“string”


      对答案再补充一点


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

      ==Operator

    • 如果操作数为且其值等于,则返回true else false
    • 如果操作数除字符串外都引用相同的实例(相同对象),则返回true else false
    • 如果操作数是字符串类型且其相等,则返回true else false
    • .Equals

    • 如果操作数为,则执行该操作,即如果两个操作数都引用相同的实例(相同的对象),则返回true else false
    • 如果操作数与==运算符不同,则首先检查它们的类型,如果它们的类型相同,则执行==运算符,否则返回false
    • 首先,有区别。数字

      > 2 == 2.0
      True
      
      > 2.Equals(2.0)
      False
      
      弦呢

      > string x = null;
      > x == null
      True
      
      > x.Equals(null)
      NullReferenceException
      

      在这两种情况下,
      =
      的行为比
      .Equals

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

      请注意,其他一些语言对两个相等检查运算符使用单独的标记。例如,在VB.NET中,
      =
      标记仅在表达式中用于重载相等检查运算符,而
      is
      用作参考测试或空测试运算符。在不覆盖相等检查运算符的类型上使用
      =
      的操作将失败,尝试将
      Is
      用于测试引用相等性或空性以外的任何目的也将失败

      (*)类型通常仅重载
      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
      
      MyString.Equals("Somestring"))          //Method 1
      MyString == "Somestring"                //Method 2
      String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better
      
         bool areEqual = String.Equals("Somestring", MyString);  
      
      public static bool Equals (string a, string b);
      
       int x = 50;
       int y = 50;
       Console.WriteLine (x == y); // True
      
       object x = 50;
       object y = 50;
       Console.WriteLine (x == y); // False 
      
      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