Equals,ReferenceEquals,==的區別

來源:互聯網
上載者:User
在.net中有幾種比較相等的方法

object的靜態ReferenceEquals()

object的靜態Equals()

object的樣本Equals()

運算子==

下面介紹一下他們的區別和用法。

ReferenceEquals

ReferenceEquals用於比較參考型別的引用是是否指向同一個對象。它只能比較參考型別。當把實值型別傳給它的時候永遠都會返回false,因為實值型別作為參數的時候首先會裝箱,經過裝箱的實值型別哪怕是指相等,但是也是兩個不同的對象,所以變數是指向不同的對象,所以永遠返回false。

int x = 10;
int y = 10;
bool b1 = object.ReferenceEquals(x,y);
這裡結果肯定是返回false,但是如果是比較參考型別,如果是兩個引用指向同一個對象,則為true。

我們還是先定義實體類

public class Person
{
private int _personId;

public int PersonId
{
get { return _personId; }
set { _personId = value; }
}

private string _firstName;

public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

private string _lastName;

public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}

public Person() { }

public Person(int personId, string firstName, string lastName)
{
this._personId = personId;
this._firstName = firstName;
this._lastName = lastName;
}
}
調用代碼

Person person1 = new Person(1,"Edrick","Liu");
Person person2 = new Person(2, "Meci", "Luo");
Person person3 = person2;
bool br1= object.ReferenceEquals(person1,person2);
bool br2 = object.ReferenceEquals(person2, person3);
我們可以發現第一個返回false,第二個返回true。那麼如果其中有一個對象為null,或者兩個對象都為null呢?結果會為false,如果兩個都為null呢?結果為true。他們不會引發異常。

執行個體Equals

執行個體Equals算是比較複雜的一個比較方法。執行個體Equals可以比較引用是否指向同一個對象,同時可以按值來比較對象。如果要按值比較對象,我們就需要重載Equals對象來實現我們的比較邏輯。同時Equals預設也支援比較實值型別的相等。那麼我們該怎麼重載Equals來讓對象具有值相等性的比較呢?

MSDN給我們列出了一些準則

除涉及浮點型的情況外,x.Equals(x) 都返回 true。

x.Equals(y) 返回與 y.Equals(x) 相同的值。

如果 x 和 y 都為 NaN,則 x.Equals(y) 返回 true。

若且唯若 x.Equals(z) 返回 true 時,(x.Equals(y) && y.Equals(z)) 才返回 true。

只要不修改 x 和 y 引用的對象,對 x.Equals(y) 的相繼調用將返回相同的值。

x.Equals(nullNothingnullptrnull 引用(在 Visual Basic 中為 Nothing)) 返回 false。

我們來看看重寫代碼

public class Person
{
private int _personId;

public int PersonId
{
get { return _personId; }
set { _personId = value; }
}

private string _firstName;

public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

private string _lastName;

public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}

public Person() { }

public Person(int personId, string firstName, string lastName)
{
this._personId = personId;
this._firstName = firstName;
this._lastName = lastName;
}

public override bool Equals(object obj)
{
if (obj != null && obj is Person)
{
Person p = obj as Person;

return (PersonId == p.PersonId) && (FirstName == p.FirstName) && (LastName == p.LastName);
}
else
{
return false;
}
}

public override int GetHashCode()
{
return base.GetHashCode()^PersonId;
}
}
調用代碼

Person person1 = new Person(1,"Edrick","Liu");
Person person2 = new Person(2, "Meci", "Luo");
Person person3 = person2;
Person person4 = new Person(1, "Edrick", "Liu");

Console.WriteLine(person4.Equals(person1));
Console.WriteLine(person4.Equals(person2));
我們可以看到結果,第一個為true,第二個為false。重載的時候不能出現異常。那麼如果有一個類繼承Person呢,我們又改如何比較衍生類別。

public class Student:Person
{
private int _studentNumber;

public int StudentNumber
{
get { return _studentNumber; }
set { _studentNumber = value; }
}

public Student() { }

public Student(int personId, string firstName, string lastName, int studentNumber)
{
this.PersonId = personId;
this.FirstName = firstName;
this.LastName = lastName;
this._studentNumber = studentNumber;
}

public override bool Equals(object obj)
{
if (obj != null && obj is Person)
{
Student s = obj as Student;
return base.Equals(obj)&&StudentNumber==s.StudentNumber;
}
else
{
return false;
}
}

public override int GetHashCode()
{
return base.GetHashCode()^StudentNumber;
}
}
調用代碼

Student s1 = new Student(1, "Edrick", "Liu", 1);
Student s2 = new Student(2, "Meci", "Luo", 2);
Student s3 = new Student(1, "Edrick", "Liu", 1);

Console.WriteLine(s1.Equals(s2));
Console.WriteLine(s1.Equals(s3));
我們只需要調用父類的Equals方法和比較衍生類別中的新值。

靜態Equals

這個方法算是比較有趣的一個方法了。這個方法也是靜態,它能比較引用,能比較實值型別。如果比較的類型重載了執行個體的Equals,那麼它也能也比較對象的值。所以它返回true有三種情況。

1,引用指向同一個對象

2,比較兩個null

3,重載了Equals的執行個體方法返回true

Student s1 = new Student(1, "Edrick", "Liu", 1);
Student s2 = new Student(2, "Meci", "Luo", 2);
Student s3 = new Student(1, "Edrick", "Liu", 1);
Student s4 = s3;

Console.WriteLine(object.Equals(s1,s3));
Console.WriteLine(object.Equals(s4, s3));
這兩個都為true,這裡靜態Equals跟靜態EqualsReference有一個區別,靜態Equals如果有一個參數為null會拋出異常。

下面討論一個有趣的現象,如果重載了Equals但是沒有重載==運算子,會發生什麼

Student s1 = new Student(1, "Edrick", "Liu", 1);
Student s2 = new Student(2, "Meci", "Luo", 2);
Student s3 = new Student(1, "Edrick", "Liu", 1);
Student s4 = s3;

Console.WriteLine(s1==s3);
Console.WriteLine(s3==s4);
第一個為false,第二個為true。這顯然不符合我們意圖,所以重載了Equals必須重載==,同樣重載了==也必須重載Equals。這樣符合我們的意圖,也能確保在使用集合的時候,代碼能按照我們的意圖工作。因為集合coll[0]==co[0]其實比較的是引用,但是如果我們的Equals比較的是對象的值那麼最後代碼還是不能按照我的期望的運行。

==運算子

==號運算子其實跟執行個體的Equals沒有多大的區別,==是運算子,而Equals是方法。他們都可以重寫。預設都能比較引用和比較值。關於==的重載可以參考運算子一文中的運算子多載。

總結他們的區別:

ReferenceEquals:靜態方法,不能重寫,只能比較引用,如果有一個參數為null會返回false,不會拋出異常,如果比較實值型別,則始終返回false。

Equals:執行個體方法,預設可以比較引用也可以比較值,可以重寫。可以按值比較對象。

靜態Equals:靜態方法,不能重寫。如果沒有重寫Equals,比較引用,或者比較值。如果重載了Equals方法。比較引用,或者比較值,或者按重寫的Equals比較,如果其中一個參數為null,拋出異常

==運算子:可以按引用比較,也可以按值比較。可以重寫。是操作運算子。

最後需要的是,如果重載了Equals,則最好是重載GetHashCode,必須重載==運算子。




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.