【问题标题】:Is List.Contains fully comparison-wise equivalent to List.IndexOf?List.Contains 在比较方面是否完全等同于 List.IndexOf?
【发布时间】:2014-04-17 12:44:00
【问题描述】:

List.Contains() 的 MSDN 描述说

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

还有List.IndexOf()的描述说

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

EqualityComparer.Default描述说

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

这有点可疑——Contains 的描述只提到了IEquatable,并且可以将未实现IEquatable 的内容放入List

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

那么它们在比较方面完全等效吗?

【问题讨论】:

    标签: c# .net list generics


    【解决方案1】:

    简答:

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

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

    List.Contains

    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);
    }
    

    EqualityComparer.IndexOf

    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>();
    }
    

    【讨论】:

      【解决方案2】:

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

      不,它没有。

      List.Contains 实现为:

      来自Reference Source .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&lt;T&gt;.IndexOf 使用 Array.IndexOf

      Source:List&lt;T&gt;.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 is implementedas

      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);
      
      }
      

      【讨论】:

        猜你喜欢
        • 2016-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-26
        • 2022-07-02
        • 1970-01-01
        • 2023-03-14
        相关资源
        最近更新 更多