我正在处理对象的IReadOnlyCollection

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

在我看来,这有点不合逻辑:我可以将元素放置在给定的位置,但是我无法获得该元素的位置。

是否有特定原因?

我已经读过-> How to get the index of an element in an IEnumerable?,但我对响应并不完全满意。

最佳答案

简单明了:
出于任何原因都没有IndexOf() 不能使用IReadOnlyList<T>
如果您真的想找到提及的理由,那么原因是历史性的:
早在90年代中期,C#被放下时,人们还没有开始意识到不变性和只读性的好处,因此不幸的是,他们烘焙到该语言中的IList<T>接口(interface)是可变的。
正确的选择是将IReadOnlyList<T>作为基本接口(interface),并让IList<T>对其进行扩展,仅添加变异方法,但事实并非如此。IReadOnlyList<T>IList<T>之后被发明了很长一段时间,到那时重新定义IList<T>并使其扩展IReadOnlyList<T>已经为时已晚。因此,IReadOnlyList<T>是从头开始构建的。
他们无法让IReadOnlyList<T>扩展IList<T>,因为那样的话,它就继承了变异方法,因此他们将其基于IReadOnlyCollection<T>IEnumerable<T>。他们添加了this[i]索引器,但是他们要么忘记添加其他方法,例如IndexOf(),要么故意将它们省略,因为它们可以实现为扩展方法,从而使接口(interface)更简单。 但他们没有提供任何此类扩展方法。
因此,这里是一个扩展方法,将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;
    }
请注意,这种扩展方法没有内置在接口(interface)中的方法那么强大。例如,如果您正在实现一个期望将IEqualityComparer<T>作为构造(或其他方式)参数的集合,则此扩展方法将非常高兴地没有意识到这一点,这当然会导致错误。 (感谢Grx70在评论中指出这一点。)

08-05 13:27