2017-07-09 15 views
7

Cân nhắc this mã:Tại sao là Array.IndexOf không kiểm tra cho IEquatable như Danh sách <T> hiện?

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; 

} 

Kết quả:

0 
-1 

Tại sao các kết quả khác nhau giữa List<T>Array? Tôi đoán đây là do thiết kế, nhưng tại sao?

Nhìn vào mã số List<T>.IndexOf làm tôi ngạc nhiên hơn nữa, vì nó đang chuyển đến Array.IndexOf.

+1

Tôi đã viết ít bài đăng về câu hỏi này: http://blog.rogatnev.net/2017/07/1 4/IndexOf-with-IEquatable.html – Backs

Trả lời

4

Thực hiện IndexOf trong phương pháp gọi lớp mảng:

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

Như bạn thấy, nó sử dụng object như tham số giá trị. Trong phương pháp này có mã:

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

Lớp làm việc với các đối tượng, vì vậy nó gọi phương thức public virtual bool Equals(object obj), không phải là phương thức chung.

Trong List lớp IndexOf sử dụng thực hiện chung:

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

Vì vậy, nó sử dụng chung Comparer chất lượng:

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

UPD: Tôi đã viết một ít bài về vấn đề này: http://blog.rogatnev.net/2017/07/14/IndexOf-with-IEquatable.html

+1

Đây là lý do tại sao bạn * luôn luôn * nên ghi đè' Equals (object) '(và' GetHashCode' mặc dù vì các lý do khác nhau) khi triển khai 'IEquatable '. Sửa chữa rất đơn giản: 'công khai override bool Equals (đối tượng khác) => Equals (khác như Item); ghi đè công khai int GetHashCode() => Id; ' –

4

Bởi vì bộ sưu tập đối tượng chung chung sử dụng giao diện IEquatable<T> khi kiểm tra cho sự bình đẳng trong các phương pháp như Contains, IndexOf, LastIndexOf, và Remove.

Mảng không biết gì về <T> để không thể triển khai hoặc sử dụng giao diện IEquatable.

Một mảng thay vì giữ các đối tượng không chung chung. Nó sẽ gọi Equals để so sánh một đối tượng với đối tượng khác vì tất cả các đối tượng đều có phương thức Equals mà bạn được tự do ghi đè.

+0

Không phải là 'T []' chung? – Shimmy

+0

Có chính xác. 'T' là generic nhưng Array thì không. Mảng chứa các đối tượng không được nhập. Vì vậy nó sẽ sử dụng object.Equals để so sánh. –

2

List<T> có thể sử dụng giao diện IEquatable<T>, để giao diện hoạt động như mong đợi.

Mảng đang sử dụng phương pháp Equals từ Object và bạn không ghi đè phương pháp đó, mà chỉ thực hiện IEquatable.

Cố gắng xác định Equals như:

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

Điều đó sẽ làm việc cho cả hai trường hợp trong cùng một cách.

+0

Bạn có thể tránh trùng lặp mã bằng cách viết 'công khai ghi đè bool Equals (đối tượng khác) => Equals (khác như Item);', và điều này không * không * ném 'NullReferenceException' nếu' other' là một đối tượng không null không phải là một mục '. –

+0

Hoặc chưa? => Khác là Mục mặt hàng? item.Id == Id: false; ' – Shimmy

Các vấn đề liên quan