简体   繁体   English

为什么 IReadOnlyCollection 有 ElementAt 但没有 IndexOf

[英]Why IReadOnlyCollection has ElementAt but not IndexOf

I am working with a IReadOnlyCollection of objects.我正在使用IReadOnlyCollection对象。

Now I'm a bit surprised, because I can use linq extension method ElementAt() .现在我有点惊讶,因为我可以使用linq扩展方法ElementAt() But I don't have access to IndexOf() .但我无权访问IndexOf()

This to me looks a bit illogical: I can get the element at a given position, but I cannot get the position of that very same element.这在我看来有点不合逻辑:我可以在给定位置获取元素,但我无法获取该元素的位置。

Is there a specific reason for it?有什么具体原因吗?

I've already read -> How to get the index of an element in an IEnumerable?我已经阅读过 -> 如何获取 IEnumerable 中元素的索引? and I'm not totally happy with the response.我对回应并不完全满意。

IReadOnlyList<T> has no IndexOf() for no good reason whatsoever . IReadOnlyList<T>没有任何理由没有IndexOf()

If you really want to find a reason to mention, then the reason is historical:如果真要找个理由提起,那是历史原因:

Back in the mid-nineties when C# was laid down, people had not quite started to realize the benefits of immutability and readonlyness, so the IList<T> interface that they baked into the language was, unfortunately, mutable.早在 90 年代中期 C# 诞生时,人们还没有完全意识到不变性和只读的好处,因此不幸的是,他们融入语言的IList<T>接口是可变的。

The right thing would have been to come up with IReadOnlyList<T> as the base interface, and make IList<T> extend it, adding mutation methods only, but that's not what happened.正确的做法是将IReadOnlyList<T>作为基本接口,并使IList<T>扩展它,仅添加突变方法,但事实并非如此。

IReadOnlyList<T> was invented a considerable time after IList<T> , and by that time it was too late to redefine IList<T> and make it extend IReadOnlyList<T> . IReadOnlyList<T>是在IList<T>之后很长时间发明的,到那时重新定义IList<T>并使其扩展IReadOnlyList<T>为时已晚。 So, IReadOnlyList<T> was built from scratch.因此, IReadOnlyList<T>是从头开始构建的。

They could not make IReadOnlyList<T> extend IList<T> , because then it would have inherited the mutation methods, so they based it on IReadOnlyCollection<T> and IEnumerable<T> instead.他们不能让IReadOnlyList<T>扩展IList<T> ,因为那样它会继承变异方法,所以他们基于IReadOnlyCollection<T>IEnumerable<T>代替。 They added the this[i] indexer, but then they either forgot to add other methods like IndexOf() , or they intentionally omitted them since they can be implemented as extension methods, thus keeping the interface simpler.他们添加了this[i]索引器,但随后他们要么忘记添加其他方法,如IndexOf() ,要么故意省略它们,因为它们可以作为扩展方法实现,从而使接口更简单。 But they did not provide any such extension methods.但是他们没有提供任何这样的扩展方法。

So, here, is an extension method that adds IndexOf() to IReadOnlyList<T> :所以,这里是一个将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;
    }

Be aware of the fact that this extension method is not as powerful as a method built into the interface would be.请注意,此扩展方法不如接口中内置的方法强大。 For example, if you are implementing a collection which expects an IEqualityComparer<T> as a construction (or otherwise separate) parameter, this extension method will be blissfully unaware of it, and this will of course lead to bugs.例如,如果您正在实现一个期望IEqualityComparer<T>作为构造(或其他独立)参数的集合,则此扩展方法将完全不知道它,这当然会导致错误。 (Thanks to Grx70 for pointing this out in the comments.) (感谢 Grx70 在评论中指出这一点。)

IndexOf is a method defined on List , whereas IReadOnlyCollection inherits just IEnumerable . IndexOf是一个在List定义的方法,而IReadOnlyCollection只继承了IEnumerable

This is because IEnumerable is just for iterating entities.这是因为IEnumerable仅用于迭代实体。 However an index doesn't apply to this concept, because the order is arbitrary and is not guaranteed to be identical between calls to IEnumerable .然而,索引不适用于这个概念,因为顺序是任意的,并且不能保证在调用IEnumerable之间是相同的。 Furthermore the interface simply states that you can iterate a collection, whereas List states you can perform adding and removing also.此外,界面只是声明您可以迭代集合,而List声明您也可以执行添加和删除操作。

The ElementAt method sure does exactly this. ElementAt方法确实做到了这一点。 However I won't use it as it reiterates the whole enumeration to find one single element.但是我不会使用它,因为它会重复整个枚举以找到一个元素。 Better use First or just a list-based approach.更好地使用First或仅使用基于列表的方法。

Anyway the API design seems odd to me as it allows an (inefficient) approach on getting an element at n -th position but does not allow to get the index of an arbitrary element which would be the same inefficient search leading to up to n iterations.无论如何,API 设计对我来说似乎很奇怪,因为它允许在第n个位置获取元素的(低效)方法,但不允许获取任意元素的索引,这与导致最多n次迭代的低效搜索相同. I'd agree with Ian on either both (which I wouldn't recommend) or neither.我同意 Ian 的观点(我不推荐)或两者都不同意。

It is because the IReadOnlyCollection (which implements IEnumerable ) does not necessarily implement indexing , which often required when you want to numerically order a List .这是因为IReadOnlyCollection (实现IEnumerable )不一定实现indexing ,当您想要对List进行数字排序时通常需要indexing IndexOf is from IList . IndexOf来自IList

Think of a collection without index like Dictionary for example, there is no concept of numeric index in Dictionary .认为,如果没有指数喜欢收藏的Dictionary例如,没有在数字指标的概念Dictionary In Dictionary , the order is not guaranteed, only one to one relation between key and value.Dictionary ,顺序是没有保证的,只有 key 和 value 之间的一一对应关系。 Thus, collection does not necessarily imply numeric indexing.因此,集合并不一定意味着数字索引。

Another reason is because IEnumerable is not really two ways traffic.另一个原因是因为IEnumerable并不是真正的两种方式的流量。 Think of it this way: IEnumerable may enumerate the items x times as you specify and find the element at x (that is, ElementAt ), but it cannot efficiently know if any of its element is located in which index (that is, IndexOf ).可以这样想: IEnumerable可能会在您指定时枚举项x次并在x处找到元素(即ElementAt ),但它无法有效地知道它的任何元素是否位于哪个索引(即IndexOf )中.

But yes, it is still pretty weird even you think it this way as would expect it to have either both ElementAt and IndexOf or none.但是,是的,它仍然是很奇怪的,即使你认为这种方式是希望它要么两者ElementAtIndexOf无。

IReadOnlyCollection<T> has ElementAt<T>() because it is an extension to IEnumerable<T> , which has that method. IReadOnlyCollection<T>具有ElementAt<T>()因为它是IEnumerable<T>的扩展,它具有该方法。 ElementAt<T>() iterates over the IEnumerable<T> a specified number of iterations and returns value as that position. ElementAt<T>()IEnumerable<T>上迭代指定次数的迭代并返回值作为该位置。

IReadOnlyCollection<T> lacks IndexOf<T>() because, as an IEnumerable<T> , it does not have any specified order and thus the concept of an index does not apply. IReadOnlyCollection<T>缺少IndexOf<T>()因为作为IEnumerable<T> ,它没有任何指定的顺序,因此索引的概念不适用。 Nor does IReadOnlyCollection<T> add any concept of order. IReadOnlyCollection<T>也不添加任何顺序概念。

I would recommend IReadOnlyList<T> when you want an indexable version of IReadOnlyCollection<T> .当您想要IReadOnlyList<T>的可索引版本时,我会推荐IReadOnlyList<T> IReadOnlyCollection<T> This allows you to correctly represent an unchangeable collection of objects with an index.这允许您使用索引正确表示不可更改的对象集合。

This could be helpful to someone:这可能对某人有帮助:

public static int IndexOf<T>(this IReadOnlyList<T> self, Func<T, bool> predicate)
{
    for (int i = 0; i < self.Count; i++)
    {
        if (predicate(self[i]))
            return i;
    }

    return -1;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么HashSet <T> 没有实现IReadOnlyCollection <T> ? - Why HashSet<T> does not implement IReadOnlyCollection<T>? 为什么字典“不包含&#39;ElementAt&#39;的定义”? - Why Dictionary “does not contain a definition for 'ElementAt'”? 为什么LINQ to SQL不支持查询运算符&#39;ElementAt&#39;? - Why is the query operator 'ElementAt' is not supported in LINQ to SQL? 为什么动态IEnumerable上的First()或ElementAt()是等待的? - Why is First() or ElementAt() on a dynamic IEnumerable awaitable? 为什么不存在ElementAt的异步版本? - Why does an async version of ElementAt not exist? 如何检查属性 elementAt() 是否有值且不为空 - How to check the property elementAt() has a value and its not null 为什么我不能分配BlockingCollection <T> 到IReadOnlyCollection <T> ? - Why cant I assign a BlockingCollection<T> to IReadOnlyCollection<T>? monoDevelop ubuntu c#类列表没有elementAt方法 - monoDevelop ubuntu c# Class List has not the elementAt method 为什么通用ICollection不在.NET 4.5中实现IReadOnlyCollection? - Why doesn't generic ICollection implement IReadOnlyCollection in .NET 4.5? 为什么我要使用 Enumerable.ElementAt() 而不是 [] 运算符? - Why would I use Enumerable.ElementAt() versus the [] operator?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM