IEnumerable泛型的扩展

See*_*eer 5 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我写这段代码:

        Pages = history.InSetsOf<Message>(500);
        var index = Pages.IndexOf(x => x == Pages.ElementAt(0));
Run Code Online (Sandbox Code Playgroud)

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

Kob*_*obi 5

当你写作时Pages.IndexOf(x => x == Pages.ElementAt(0));,由于延迟执行(又称懒惰),你实际上会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();
Run Code Online (Sandbox Code Playgroud)

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

Pages = history.InSetsOf<Message>(500);
var firstPage = Pages.FirstOrDefault();
var index = Pages.IndexOf(x => x.SequenceEqual(firstPage));
Run Code Online (Sandbox Code Playgroud)