642

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

这是代码:

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

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

为什么会发生这种情况?

4

19 回答 19

493

==用于类型的表达式时object,它会解析为System.Object.ReferenceEquals.

Equals只是一种virtual方法并且行为如此,因此将使用覆盖的版本(用于string比较内容的类型)。

于 2009-05-02T13:39:29.853 回答
381

在将对象引用与字符串进行比较时(即使对象引用引用了字符串),==特定于字符串类的运算符的特殊行为将被忽略。

通常(即不处理字符串时)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
于 2009-05-02T13:40:30.193 回答
57

==并且.Equals都依赖于实际类型中定义的行为和调用站点的实际类型。两者都只是方法/运算符,可以在任何类型上重写并给出作者想要的任何行为。根据我的经验,我发现人们.Equals在对象上实现但忽略实现 operator是很常见的==。这意味着.Equals将实际测量值的相等性,同时==将测量它们是否是相同的参考。

当我使用定义不断变化的新类型或编写通用算法时,我发现最佳实践如下

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

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

Eric Lippert 最近发表了一篇关于为什么 CLR 中有两种相等方法的博客文章。值得一读

于 2009-05-02T13:47:46.667 回答
33

== 运算符

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

。等于

  1. 如果操作数是引用类型,则执行引用相等,即如果两者都引用同一个实例(同一个对象),则返回 true,否则返回 false。
  2. 如果操作数是值类型,则与 == 运算符不同,它首先检查它们的类型,如果它们的类型相同,则执行 == 运算符,否则返回 false。
于 2012-10-11T07:54:23.153 回答
25

据我了解,答案很简单:

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

我希望我是正确的,它回答了你的问题。

于 2016-11-27T09:56:45.453 回答
20

首先,有区别。对于数字

> 2 == 2.0
True

> 2.Equals(2.0)
False

对于字符串

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

> x.Equals(null)
NullReferenceException

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

于 2013-08-15T11:15:44.410 回答
15

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

可能的意外参考比较;要进行值比较,请将左侧转换为“字符串”

于 2011-08-11T03:35:44.653 回答
7

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

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

来自 VS2017 的示例

于 2019-06-03T13:40:24.143 回答
6

因为到目前为止还没有提到该方法的静态版本,.Equal所以我想在此处添加它以总结和比较 3 种变体。

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

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

背景信息和总结:

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

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

建议的解决方案:

因为 using与比较事物时==的 using 并不完全相同.Equals,所以您可以使用静态 String.Equals方法来代替。这样,如果两边不是同一个类型,你仍然会比较内容,如果一个为空,你将避免异常。

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

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

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

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

参数

a 细绳

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

b 细绳

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

退货 Boolean

true如果 的值与a的值相同b;否则,false。如果两者都是a,则该方法返回。bnulltrue

于 2017-11-16T19:48:25.057 回答
2

我在这里有点困惑。如果 Content 的运行时类型是字符串类型,那么 == 和 Equals 都应该返回 true。但是,由于情况并非如此,因此 Content 的运行时类型不是字符串,并且在其上调用 Equals 正在执行引用相等,这解释了 Equals("Energy Attack") 失败的原因。然而,在第二种情况下,关于应该调用哪个重载的 == 静态运算符的决定是在编译时做出的,这个决定似乎是 ==(string,string)。这向我表明 Content 提供了对字符串的隐式转换。

于 2009-05-02T16:02:44.283 回答
2

为答案再添一分。

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

于 2012-07-11T11:04:21.103 回答
2

@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
于 2015-01-26T09:12:56.013 回答
1

真的很棒的答案和例子!

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

运算符如==不是多态的,Equals而是

考虑到这个概念,如果您提出任何示例(通过查看左手和右手引用类型,并检查/了解该类型是否实际上重载了 == 运算符并且 Equals 被覆盖),您肯定会得到正确的答案.

于 2015-04-15T09:10:38.837 回答
1

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

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

所以现在更容易理解了,equal 方法也有两种实现,一种来自字符串类本身,一种来自对象类。它对性能的影响以及我还运行一些基本代码并尝试了解基准。

我在下面分享结果如果我在某处错了,请更正或建议。有 3 个案例,我为所有案例运行了相同的代码,这就是结果。

案例1:这里我使用的是字符串。equal 方法比较两个字符串并且两个字符串具有相同的值。string.equals(a,b)

第一次运行:5608195 滴答

第二次运行:5529387 滴答声

第三次运行:5622569 滴答声

总刻度:16760151

案例2:这里我使用的是字符串。equal() 方法(重载一个)用于比较 2 个字符串并且两个字符串具有相同的值。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++;
        }
    }
}
于 2021-07-09T13:31:35.750 回答
0

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

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

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

于 2014-02-14T17:47:05.593 回答
-1

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

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

于 2014-03-20T04:31:40.277 回答
-1

请注意,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()使用结构比较 for struct,这意味着它在结构的每个字段上调用 ​​Equals。

于 2021-01-29T19:06:28.540 回答
-2

==

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

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对象,都代表“简”中的字符

于 2014-11-15T11:34:26.483 回答
-2

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

对象:等于:按位相等 ==:引用相等

string: (equals 和 == 对于 string 是一样的,但是如果 string 之一变成了 object,那么比较结果会不同) Equals: 按位相等 == : 按位相等

有关更多说明,请参见此处

于 2014-12-30T02:11:37.837 回答