我正在处理对象的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>
:
请注意,这种扩展方法没有内置在接口(interface)中的方法那么强大。例如,如果您正在实现一个期望将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;
}
IEqualityComparer<T>
作为构造(或其他方式)参数的集合,则此扩展方法将非常高兴地没有意识到这一点,这当然会导致错误。 (感谢Grx70在评论中指出这一点。)