IEnumerable泛型的扩展

时间:2011-11-24 07:02:40

标签: c# ienumerable

我有两个IEnumerable扩展名:

public static class IEnumerableGenericExtensions
{
    public static IEnumerable<IEnumerable<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
    {
        List<T> toReturn = new List<T>(max);
        foreach (var item in source)
        {
            toReturn.Add(item);
            if (toReturn.Count == max)
            {
                yield return toReturn;
                toReturn = new List<T>(max);
            }
        }
        if (toReturn.Any())
        {
            yield return toReturn;
        }
    }

    public static int IndexOf<T>(this IEnumerable<T> source, Predicate<T> searchPredicate)
    {
        int i = 0;
        foreach (var item in source)
            if (searchPredicate(item))
                return i;
            else
                i++;

        return -1;
    }
}

然后我写下这段代码:

        Pages = history.InSetsOf<Message>(500);
        var index = Pages.IndexOf(x => x == Pages.ElementAt(0));

,其中     公共类历史:IEnumerable 但结果我没有像我预期的那样'0',而是'-1'。我不明白 - 为什么会这样?

2 个答案:

答案 0 :(得分:5)

当你写Pages.IndexOf(x => x == Pages.ElementAt(0));时,由于deferred execution(又是懒惰),你实际上多次运行InSetsOf 。要扩展:

  • Pages = history.InSetsOf<Message>(500) - 此行根本不会运行InSetsOf
  • Pages.IndexOf - 迭代Pages,因此它开始执行InSetsOf一次。
  • x == Pages.ElementAt(0) - 这会再次执行InSetsOf,对Pages集合中的每个元素执行一次(或者至少直到searchPredicate返回true,这在此处不会发生)。

每次运行InSetsOf时,您都会创建一个新列表(具体来说,是一个新的第一个列表,因为您使用的是ElementAt(0))。这是两个不同的对象,因此它们之间==的比较失败。

一个非常简单的修复方法是返回一个列表,因此Pages不是延迟查询,而是具体集合:

Pages = history.InSetsOf<Message>(500).ToList();

另一种选择是使用SequenceEqual,不过我建议缓存第一个元素:

Pages = history.InSetsOf<Message>(500);
var firstPage = Pages.FirstOrDefault();
var index = Pages.IndexOf(x => x.SequenceEqual(firstPage));

答案 1 :(得分:1)

你的班级T是否实施了IComparable?如果没有,你的等式检查可能会有缺陷,因为框架不知道T = T的确切时间。你也可以通过重写你的类T上的等于我猜测。