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

时间:2009-05-02 13:36:58

标签: c# .net equals

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

以下是代码:

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

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

为什么会发生这种情况的原因?

19 个答案:

答案 0 :(得分:396)

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

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

答案 1 :(得分:278)

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

通常(当不处理字符串时),Equals比较,而==比较对象引用。 如果您要比较的两个对象是指对象的同一个确切实例,则两者都将返回true,但如果一个具有相同的内容并来自不同的源(是具有相同数据的单独实例),则只有Equals将返回true。但是,正如注释中所指出的,string是一种特殊情况,因为它覆盖了==运算符,因此当纯粹使用字符串引用(而不是对象引用)进行处理时,只有值才会进行比较,即使它们是单独的实例。以下代码说明了行为的细微差别:

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));

输出结果为:

True True True
False True True
False False True

答案 2 :(得分:44)

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

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

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

在某些情况下,当我觉得==的使用含糊不清时,我会在代码中明确使用Object.Reference等号来消除歧义。

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

答案 3 :(得分:18)

首先,的区别。对于数字

> 2 == 2.0
True

> 2.Equals(2.0)
False

对于字符串

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

> x.Equals(null)
NullReferenceException

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

更有用

答案 4 :(得分:12)

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

  

可能的意外参考比较;得到一个价值比较,   施放左侧以输入'string'

答案 5 :(得分:9)

==运算符 1.如果操作数为Value Types并且它们的值相等,则返回true,否则返回false。 2.如果操作数为Reference Types且字符串除外,并且两者都引用同一对象,则返回true,否则返回false。 3.如果操作数是字符串类型且它们的值相等,则返回true,否则返回false。

<强> .Equals 1.如果操作数是引用类型,则执行Reference Equality,如果两者都引用同一对象,则返回true,否则返回false。 2.如果操作数是值类型,那么与==运算符不同,它首先检查它们的类型,如果它们的类型相同则执行==运算符,否则返回false。

答案 6 :(得分:9)

据我所知,答案很简单:

  1. ==比较对象引用。
  2. .Equals比较对象内容。
  3. 字符串数据类型总是像内容比较一样。
  4. 我希望我是正确的,并且它回答了你的问题。

答案 7 :(得分:4)

由于到目前为止尚未提及.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比较字符串没有实际区别,只要两者都是字符串类型。但是,如果一个为null,一个是另一个类型(如整数),或者一个代表具有不同引用的对象,那么,如初始问题所示,您可能会遇到比较内容的相等性可能不会返回什么你期待。

建议的解决方案:

因为在比较时使用==与使用.Equals不完全相同,所以您可以使用 static String.Equals 方法。这样,如果双方不是同一类型,你仍然会比较内容,如果一个为null,你将避免异常。

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

写一点,但在我看来,使用更安全。

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

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

参数

a字符串

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

b字符串

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

返回Boolean

如果true的值与a的值相同,则

b;否则,false。如果ab都是null,则该方法会返回true

答案 8 :(得分:2)

我在这里有点困惑。如果Content的运行时类型是string类型,则==和Equals都应返回true。但是,由于情况似乎并非如此,因此Content的运行时类型不是字符串,并且调用Equals就可以执行引用相等,这就解释了Equals(“Energy Attack”)失败的原因。但是,在第二种情况下,应该在编译时决定调用哪个重载==静态运算符,并且此决定似乎是==(字符串,字符串)。这告诉我内容提供了对字符串的隐式转换。

答案 9 :(得分:2)

再添加一个答案。

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

答案 10 :(得分: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

答案 11 :(得分:1)

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

== 在 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++;
        }
    }
}

答案 12 :(得分:1)

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

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

Example From VS2017

答案 13 :(得分:0)

非常好的答案和例子!

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

  

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

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

答案 14 :(得分:0)

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

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

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

答案 15 :(得分:-1)

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

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

答案 16 :(得分:-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()struct 使用结构比较,这意味着它对结构的每个字段调用 Equals。

答案 17 :(得分:-2)

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

对象: 等于:逐位平等 ==:引用相等

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

有关详细说明,请参阅here

答案 18 :(得分:-2)

<强> ==

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

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

注意:int的左侧有更多的零,但我们不在乎这里。

int a(00000011)== byte 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对象,它们都代表&#34; Jane&#34;

中的字符