为什么IReadOnlyCollection具有ElementAt但不具有IndexOf

Lor*_*oro 6 c# linq extension-methods readonly-collection

我正在处理IReadOnlyCollection一些对象.

现在我有点惊讶,因为我可以使用linq扩展方法ElementAt().但我无法访问IndexOf().

这对我来说看起来有点不合逻辑:我可以在给定位置获取元素,但我无法获得该元素的位置.

它有具体原因吗?

我已经读过 - > 如何获取IEnumerable中元素的索引?我对这个回应并不满意.

Mik*_*kis 33

IReadOnlyList<T>没有IndexOf() 任何好的理由

如果真要找个理由提起,那是历史原因:

早在 90 年代中期 C# 诞生时,人们还没有完全意识到不变性和只读的好处,因此IList<T>不幸的是,他们融入语言的界面是可变的。

正确的做法是提出IReadOnlyList<T>作为基本接口,并IList<T>扩展它,仅添加突变方法,但事实并非如此。

IReadOnlyList<T>在相当长的一段时间后才发明IList<T>,到那时重新定义IList<T>和扩展为时已晚IReadOnlyList<T>。所以,IReadOnlyList<T>是从头开始构建的。

他们不能 make IReadOnlyList<T>extend IList<T>,因为那样它会继承变异方法,所以他们基于IReadOnlyCollection<T>andIEnumerable<T>取而代之。他们添加了this[i]索引器,但随后他们要么忘记添加其他方法,如IndexOf(),要么故意省略它们,因为它们可以作为扩展方法实现,从而使接口更简单。但是他们没有提供任何这样的扩展方法。

所以,这里是一个扩展方法,添加IndexOf()IReadOnlyList<T>

using Collections = System.Collections.Generic;

    public static int IndexOf<T>( this Collections.IReadOnlyList<T> self, T elementToFind )
    {
        int i = 0;
        foreach( T element in self )
        {
            if( Equals( element, elementToFind ) )
                return i;
            i++;
        }
        return -1;
    }
Run Code Online (Sandbox Code Playgroud)

请注意,此扩展方法不如接口中内置的方法强大。例如,如果您正在实现一个集合,它需要一个IEqualityComparer<T>作为构造(或其他独立)参数的集合,这个扩展方法将完全不知道它,这当然会导致错误。(感谢 Grx70 在评论中指出这一点。)

  • 让我觉得很有趣的是,stackoverflow 上的答案试图为为什么某个 API 以某种方式存在提供理由,就好像该 API 总是正确的,就好像它是用完美的智慧构建的一样,所以必须始终有一些理由可以找到并向提出问题的假定新手进行解释。 (6认同)
  • (他们通常根本不是新手,他们提出问题通常是因为他们看到 API 有问题,通过提出问题来指出问题总是被认为比咆哮更有礼貌,这就是我的观点一般更喜欢这样做。) (5认同)
  • 由于历史原因,许多 .NET API 变得混乱且过于复杂。我希望看到后续主要版本的清晰剪辑。兼容性很好,但不以延续 90 年代的设计错误为代价 (3认同)
  • @user1969177 您不能假设接口是不可变的。接口最多可以是“不可修改的”或“只读的”。它只是一个不可变的类。 (2认同)