IGrouping ElementAt与方括号运算符

时间:2015-10-27 17:24:19

标签: c# igrouping

IGrouping支持ElementAt方法来索引分组的集合。那么为什么方括号运算符不起作用呢?

我可以做类似

的事情
 list.GroupBy(expr).Select(group => group.ElementAt(0)....) 

但不是

 list.GroupBy(expr).Select(group => group[0]....) 

我猜这是因为IGrouping接口不会使方括号运算符超载。为什么IGrouping 没有重载方括号运算符来执行与ElementAt相同的操作有充分的理由吗?

4 个答案:

答案 0 :(得分:2)

这是因为GroupBy返回IEnumerable。 IEnumerables没有索引访问器<​​/ p>

答案 1 :(得分:2)

ElementAt<T>IEnumerable<T>上的标准扩展方法,它不是IGrouping上的方法,但由于IGrouping派生自IEnumerable<T>,因此效果很好。没有[]扩展方法,因为它不受C#支持(它将是索引属性,而不是方法)

答案 2 :(得分:1)

这有点回到前面,所有的枚举都得到了支持(而不是支持,因为它是外部提供的扩展方法)ElementAt()但只有一些属于还支持[],例如List<T>或任何实现IList<T>的内容。

Grouping当然可以很容易地实现[],但是它必须始终这样做,因为API将是一个它必须继续保留的承诺,否则会破坏编写的代码如果它确实打破了它的旧方式。

ElementAt()采用了一种测试和使用方法,如果某些内容支持IList<T>,它将使用[],否则它将计算相应的数字。由于您可以计算任何序列,因此它可以支持任何可枚举。

恰好Grouping支持IList<T>,但作为显式接口,以下工作原理:

//Bad code for demonstration purpose, do not use:
((IList<int>)Enumerable.Range(0, 50).GroupBy(i => i / 5).First())[3]

但是因为它显而易见,如果在另一种方法中找到了优势,它就不必继续支持它。

ElementAt的测试和使用方法:

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
{
    if (source == null) throw Error.ArgumentNull("source");
    IList<TSource> list = source as IList<TSource>;
    if (list != null) return list[index];
    if (index < 0) throw Error.ArgumentOutOfRange("index");
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
        while (true)
        {
            if (!e.MoveNext()) throw Error.ArgumentOutOfRange("index");
            if (index == 0) return e.Current;
            index--;
        }
    }
}

因此,从中获取最佳的O(1)行为,而不是O(n)行为,否则不会限制Grouping做出设计师可能后来后悔的承诺。

答案 3 :(得分:0)

ElementAt是为IEnumerable<T>定义的扩展方法(btw非常低效),为本身不支持它的序列提供伪索引访问。由于从IGrouping<TKey, TElement>方法返回的GroupBy继承IEnumerable<TElement>,您可以使用ElementAt方法。但当然IEnumerable<T>没有定义索引器,所以这就是你不能使用[]的原因。

更新:只是为了澄清“非常低效”的含义 - 实现是最好的,但是方法本身通常用于本身不支持索引器的序列。例如

var source = Enumerable.Range(0, 1000000);
for (int i = 0, count = source.Count(); i < count; i++)
{
    var element = source.ElementAt(i);
}