2017-07-09 46 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

相关问题