Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ Skip仍然枚举跳过的项_C#_.net_Linq - Fatal编程技术网

C# LINQ Skip仍然枚举跳过的项

C# LINQ Skip仍然枚举跳过的项,c#,.net,linq,C#,.net,Linq,在以下测试中: int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; Func<int, int> boom = x => { Console.WriteLine(x); return x; }; var res = data.Select(boom).Skip(3).Take(4).ToList(); Console.WriteLine(); res.Select(boom).ToList(); 本质上,我观察到在这个例子中,Ski

在以下测试中:

int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Func<int, int> boom = x => { Console.WriteLine(x); return x; };
var res = data.Select(boom).Skip(3).Take(4).ToList();
Console.WriteLine();
res.Select(boom).ToList();
本质上,我观察到在这个例子中,Skip和Take工作得很好,Skip不像Take那么懒惰。Skip似乎仍然枚举跳过的项,即使它不返回它们

同样的道理,如果我先采取行动的话。我的最佳猜测是,它至少需要列举第一次跳过或执行,以便查看下一次跳过或执行的位置

它为什么会这样做?

跳过并采取这两种方法对IEnumerable进行操作

IEnumerable不支持向前跳过-它一次只能给您一个项目。考虑到这一点,您可以将跳过更多地视为一个过滤器——它仍然会涉及源序列中的所有项,但它会过滤掉您告诉它的任何项。重要的是,它会过滤掉他们,使他们无法进入下一个目标,而不是前面的目标

因此,通过这样做:

data.Select(boom).Skip(3)
在每个项目到达跳过过滤器之前,您正在对其执行boom操作

如果改为此,它将在选择之前过滤,并且您将仅对其余项目调用boom:

data.Skip(3).Take(4).Select(boom)

假设我正确理解了你的问题

boom func在跳过操作之前执行


尝试在skip and take之后选择数据,您将得到准确的数据。

它们都迭代收集。然后是最后一集。它就像一个简单的for循环,其中包含if-else条件

此外,当您首先使用boom选择它时,它会打印集合项

通过此示例,您无法判断skip或take是否迭代整个集合,但事实上,它们确实迭代了整个集合。

如果您对Enumerable进行反编译,您将看到skip的以下实现:

以及采取以下措施:


因此,这两个LINQ方法实际上都是通过这些项枚举的。区别在于枚举项是否将放置在结果集合中。这就是IEnumerable的工作原理

不是答案,但想想Skip是如何。。。将予以实施。这里有一种方法:

public static IEnumerable<T> Skip<T>(this IEnumerable<T> list, int count)
{
    foreach (var item in list)
    {
        if (count > 0) count--;
        else yield return item;
    }
}

请注意,即使只返回一个子集,也会枚举整个列表参数。

此行为可能会在将来发生更改,正如在本次关于拉动请求的讨论中所看到的,该请求优化了实现IList接口的源的Skip方法的行为。

,Skipn通过请求下一个元素n次来工作。下一个元素来自您的选择。有些收藏品可能会“跃进”,但不是全部。如果集合是由自定义枚举器生成的呢?Skip不是将索引增加n或类似的值。Skip只是告诉枚举数给下一个项n次,而不将这些值存储在结果数组中。@ericosg我不主张为Skip使用自定义枚举数,我是说Skip不可能直接向前跳转n个项,由于自定义枚举数之类的原因。@ericosg您可以自己编写扩展:-基本上应该是公共静态IEnumerable,其中IEnumerable source>,Func谓词,int index{return source.Skipindex.Wherepredicate;}-然后像任何其他LINQ方法一样使用它。不要进行有副作用的投影。存在预测是为了产生结果,而不是副作用。正如你所发现的那样,具有副作用的投影行为确实非常奇怪。是的,我知道如果我在选择后跳过/接受,它会如预期的那样工作,但我想知道为什么visa versa不会工作。来回答你的问题,同时执行var res=data.Selectboom.Skip3.Take4.ToList的结果;动臂功能总共执行了七次,3次用于跳过,4次用于取出,以便打印。过滤数组的最终结果。我想它仍然比Where好,因为它会遍历所有10个元素来获得迭代器。i、 e.var res=data.Selectboom.Wherex,i=>i>=3&&i<7.ToList;vs var res=数据。其中x,i=>i>=3&&i<7.Selectboom.ToList;就所接触的项目而言,Where和Skip实际上应该没有区别。Where和Take之间会有明显的区别。确实如此。您的反编译器找到了一种非常详细的方法来表示if-count==0 break;Skip方法的实现是-referencesource。@CoryNelson感谢您的改进:我已经编辑了我的答案。这就是Resharper的工作原理。
while (count > 0 && e.MoveNext())
  --count;
foreach (TSource source1 in source)
{
  yield return source1;
  if (--count == 0) break;
}
public static IEnumerable<T> Skip<T>(this IEnumerable<T> list, int count)
{
    foreach (var item in list)
    {
        if (count > 0) count--;
        else yield return item;
    }
}