1

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

我可以做类似的事情

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

但不是

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

我猜这是因为 IGrouping 接口不会重载方括号运算符。IGrouping没有重载方括号运算符来做与 相同的事情有充分的理由ElementAt吗?

4

4 回答 4

2

那是因为 GroupBy 返回一个IEnumerable。IEnumerables 没有索引访问器

于 2015-10-27T17:33:24.407 回答
2

ElementAt<T>是 on 的标准扩展方法IEnumerable<T>,它不是 on 的方法IGrouping,但由于IGrouping派生自IEnumerable<T>,它可以正常工作。没有 [] 扩展方法,因为 C# 不支持它(它将是索引属性,而不是方法)

于 2015-10-27T17:39:04.677 回答
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于做出设计者以后可能会后悔的承诺。

于 2015-10-27T17:49:05.940 回答
0

ElementAt是一种扩展方法(顺便说一句,效率非常低),用于IEnumerable<T>为本身不支持它的序列提供伪索引访问。由于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);
}
于 2015-10-27T17:40:03.640 回答