是List.包含完全相当于List.IndexOf的比较

本文关键字:List 比较 IndexOf 包含完 相当于 | 更新日期: 2023-09-27 17:58:50

MSDN对List.Contains()的描述显示

此方法通过使用默认的相等比较器来确定相等,该比较器由对象对T(列表中值的类型)的IEquatable.Equals方法的实现定义。

List.IndexOf()的描述显示

此方法使用默认的相等比较器EqualityComparer确定相等。默认值为T,即列表中值的类型。

和EqualityComparer。默认描述显示

Default属性检查类型T是否实现了System.IEquatable接口,如果实现了,则返回使用该实现的EqualityComparer。否则,它返回一个EqualityComparer,它使用T.提供的Object.Equals和Object.GetHashCode的重写

这有点可疑——Contains的描述只提到了IEquatable,并且有可能将不实现IEquatable的东西放入List中。

所以我猜他们只是使用了相同的语义,也许Contains()重用了IndexOf()

那么,在比较方面,它们是否完全等效?

是List.包含完全相当于List.IndexOf的比较

简短回答:

  • 否,Contains()不重复使用IndexOf()
  • 是的,它们在比较方面是等效的

我进行了反编译(ReSharper),发现最终两者都使用了抽象的EqualityComparer<T>.Default.Equals(T x, T y)方法。根据类型T初始化(并缓存)EqualityComparer<T>Default实例。

列表。包含

EqualityComparer<T> @default = EqualityComparer<T>.Default;
// for loop
if (@default.Equals(this._items[index], item))
    return true;

List.IndexOf

return Array.IndexOf<T>(this._items, item, 0, this._size);

Array.IndexOf

public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
{
    // Some assertions
    return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
}

的均衡器比较器索引

internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
{
    // for loop
    if (this.Equals(array[index], value))
        return index;
}

这就是EqualityComparer.Default实例化的方式

public static EqualityComparer<T> Default
{
  get
  {
    EqualityComparer<T> equalityComparer = EqualityComparer<T>.defaultComparer;
    if (equalityComparer == null)
    {
      equalityComparer = EqualityComparer<T>.CreateComparer();
      EqualityComparer<T>.defaultComparer = equalityComparer;
    }
    return equalityComparer;
  }
}
private static EqualityComparer<T> CreateComparer()
{
  RuntimeType genericParameter1 = (RuntimeType) typeof (T);
  if ((Type) genericParameter1 == typeof (byte))
    return (EqualityComparer<T>) new ByteEqualityComparer();
  // Some ifs go on
  else
    return (EqualityComparer<T>) new ObjectEqualityComparer<T>();
}

所以我猜他们只是使用了相同的语义,也许还有Contains()重用IndexOf()。

不,没有。

List.Contains实现为:

来自参考源.NET Framework 4.5.1-Microsoft

public bool Contains(T item) {
    if ((Object) item == null) {
        for(int i=0; i<_size; i++)
            if ((Object) _items[i] == null)
                return true;
        return false;
    }
    else {
        EqualityComparer<T> c = EqualityComparer<T>.Default;
        for(int i=0; i<_size; i++) {
            if (c.Equals(_items[i], item)) return true;
        }
        return false;
    }
}

其中List<T>.IndexOf使用Array.IndexOf

来源:List<T>.IndexOf

public int IndexOf(T item)
{
    Contract.Ensures(Contract.Result<int>() >= -1);
    Contract.Ensures(Contract.Result<int>() < Count);
    return Array.IndexOf(_items, item, 0, _size);
}

Array.IndexOf实现为

public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
{
    if (array == null)
    {
        throw new ArgumentNullException("array");
    }
    if (startIndex < 0 || startIndex > array.Length)
    {
        throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
    }
    if (count < 0 || count > array.Length - startIndex)
    {
        throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
    }
    Contract.Ensures(Contract.Result<int>() < array.Length);
    Contract.EndContractBlock();
    return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);
}