2017-07-09 45 views
7

考慮this代碼:爲什麼Array.IndexOf沒有檢查像List <T>這樣的IEquatable呢?

public static void Main() 
{ 
    var item = new Item { Id = 1 }; 

    IList list = new List<Item> { item }; 
    IList array = new[] { item }; 

    var newItem = new Item { Id = 1 }; 

    var lIndex = list.IndexOf(newItem); 
    var aIndex = array.IndexOf(newItem); 

    Console.WriteLine(lIndex); 
    Console.WriteLine(aIndex); 
} 

public class Item : IEquatable<Item> 
{ 
    public int Id { get; set; } 

    public bool Equals(Item other) => other != null && other.Id == Id; 

} 

結果:

0 
-1 

爲什麼List<T>Array之間不同的結果?我想這是設計,但爲什麼?

看看List<T>.IndexOf的代碼讓我更想知道,因爲它將移植到Array.IndexOf

+1

我寫了一篇關於這個問題的帖子:http://blog.rogatnev.net/2017/07/1 4/IndexOf-with-IEquatable.html – Backs

回答

4

實現:

public static int IndexOf(Array array, object value, int startIndex, int count)

正如你看到的,它使用object作爲值參數。在這種方法中有代碼:

object obj = objArray[index]; 
if (obj != null && obj.Equals(value)) 
    return index; 

班組長與工作對象,所以它調用public virtual bool Equals(object obj)方法,而不是普通的一個。

IndexOfList類使用通用的實現:

public static int IndexOf<T>(T[] array, T value, int startIndex, int count) 

所以,它採用通用的質量比較器:

EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count); 

UPD:我寫了一篇關於這個問題有點崗位:http://blog.rogatnev.net/2017/07/14/IndexOf-with-IEquatable.html

+1

這就是爲什麼在執行'IEquatable '時,你總是應該重寫'Equals(object)'(和'GetHashCode')。非常簡單的修復:'公衆覆蓋布爾等於(對象其他)=>等於(其他作爲項目); public override int GetHashCode()=> Id;' –

4

因爲通用對象的集合在這樣的方法如ContainsIndexOfLastIndexOfRemove平等測試時使用IEquatable<T>接口。

Array對<T>一無所知,所以它不能實現或使用IEquatable接口。

數組反而保存​​不是通用的對象。它將調用Equals將一個對象與另一個對象進行比較,因爲所有對象都有一個可以自由覆蓋的方法Equals

+0

不是'T []'通用的嗎? – Shimmy

+0

是的。 'T'是通用的,但Array不是。數組包含未輸入的對象。因此它會使用object.Equals進行比較。 –

2

List<T>可以使用IEquatable<T>接口,以便按預期工作。

該陣列使用ObjectEquals方法,並且您不是重寫那一個,而只是實施IEquatable

嘗試定義Equals像:

public override bool Equals(Object other) => other != null && (other as Item).Id == Id; 

這將爲以同樣的方式這兩種情況下工作。在數組類調用方法的IndexOf

+0

你可以通過編寫'public override bool Equals(object other)=> Equals(other作爲Item);'來避免代碼重複,如果'other'是一個非null對象,它就會* not * throw'NullReferenceException不是'Item'。 –

+0

還是'=>其他是項目項? item.Id == Id:false;' – Shimmy

相關問題