关于c#:.Equals和==之间有什么区别

What is the difference between .Equals and ==

本问题已经有最佳答案,请猛点这里访问。

对于值类型、引用类型和字符串,a.Equals(b)a == b有什么区别?看起来a==b对字符串的作用很好,但我正在尝试使用良好的编码实践。


从什么时候开始我应该使用equals,什么时候应该使用==:

The Equals method is just a virtual
one defined in System.Object, and
overridden by whichever classes choose
to do so. The == operator is an
operator which can be overloaded by
classes, but which usually has
identity behaviour.

For reference types where == has not
been overloaded, it compares whether
two references refer to the same
object - which is exactly what the
implementation of Equals does in
System.Object.

Value types do not provide an overload
for == by default. However, most of
the value types provided by the
framework provide their own overload.
The default implementation of Equals
for a value type is provided by
ValueType, and uses reflection to make
the comparison, which makes it
significantly slower than a
type-specific implementation normally
would be. This implementation also
calls Equals on pairs of references
within the two values being compared.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

public class Test
{
    static void Main()
    {
        // Create two equal but distinct strings
        string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
        string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'});

        Console.WriteLine (a==b);
        Console.WriteLine (a.Equals(b));

        // Now let's see what happens with the same tests but
        // with variables of type object
        object c = a;
        object d = b;

        Console.WriteLine (c==d);
        Console.WriteLine (c.Equals(d));
    }
}

这个短样本程序的结果是

1
2
3
4
True
True
False
True


下面是一篇关于实现为何不同的伟大博客文章。

实际上,==将在编译时使用变量的类型进行绑定,而.equals将在运行时进行动态绑定。


在最简短的回答中:

==操作员检查身份。(即:a==b这两个是同一个对象吗?)

.equals()用于检查值。(即:A等于(B)是否都保持相同的值?)

有一个例外:对于字符串和预定义的值类型(如int、float等),运算符==将回答值而不是标识。(与使用.equals()相同)


它们之间的一个显著区别是,==是一个静态二进制运算符,用于一个类型的两个实例,而Equals是一个实例方法。这很重要的原因是你可以这样做:

1
2
3
Foo foo = new Foo()
Foo foo2 = null;
foo2 == foo;

但你不能不扔一个NullReferenceException

1
2
3
Foo foo = new Foo()
Foo foo2 = null;
foo2.Equals(foo);


在一个简单的级别上,不同之处在于调用的是哪个方法。如果为相关类型定义了==方法,则该方法将尝试不绑定到运算符==上。如果找不到值类型的==值,它将进行值比较;对于引用类型,它将进行引用比较。.equals调用将对.equals方法执行虚拟调度。

至于特定的方法做什么,都在代码中。用户可以定义/重写这些方法,并做任何他们想做的事情。理想情况下,这种方法应该是等效的(对双关语表示歉意),并且具有相同的输出,但情况并非总是如此。


有一个简单的方法可以帮助记住这个区别:a.Equals(b)更类似于a == (object)b

.Equals()方法不是泛型方法,它接受类型为"object"的参数,因此与==运算符比较时,必须将其视为右手操作数首先转换为object。

一个暗示是,无论类型如何,aba.Equals(b)几乎总是会返回一些值(如果b是一个未知类型,正常的过载方式就是返回false)。如果这些类型没有可用的比较,a == b只会抛出一个异常。


默认情况下,==.Equals()除了在null实例上调用.Equals()的可能性(这将给您一个NullReferenceException实例)外,都是等效的。但是,您可以独立地覆盖它们中的任何一个的功能(尽管我不确定这是否是一个好主意,除非您试图解决另一个系统的缺点),这意味着您可以使它们与众不同。

你会发现过道两边都有人在说要用的那个。我更喜欢运算符而不是函数。

不过,如果你说的是字符串,那么最好使用string.Compare()而不是这些选项中的任何一个。


对于字符串,您需要注意特定于区域性的比较。典型的例子是德国双精度s,它看起来有点像b。这应该与"ss"匹配,但不在简单的==比较中。

对于区域性敏感的字符串比较,请使用:string.compare(应为,value,stringcomparison…..)=0?使用StringComparison重载。


"==是一个可以根据所比较的类型重载以执行不同操作的运算符。

"==执行的默认操作是EDOCX1〔2]

以下是如何为字符串类型重载此运算符:

1
2
3
4
public static bool operator == (string str1, string str2)
{
    return (str1.Length == str2.Length;)
}

注意这与str1.Equals(str2);不同。

派生类也可以重写和重新定义Equals()

就"最佳实践"而言,这取决于您的意图。