C# 我可以使用无限范围并在其上操作吗? Enumerable.Range(0,int.MaxValue) .Select(n=>Math.Pow(n,2)) .式中(平方=>平方%2!=0) .TakeWhile(平方=>平方

C# 我可以使用无限范围并在其上操作吗? Enumerable.Range(0,int.MaxValue) .Select(n=>Math.Pow(n,2)) .式中(平方=>平方%2!=0) .TakeWhile(平方=>平方,c#,linq,C#,Linq,这段代码将迭代从0到max range的所有整数值,还是只遍历整数值以满足take-while、where和select运算符? 有人能澄清一下吗 编辑:我第一次尝试确保它按预期工作是愚蠢的。我撤销它:)int.MaxValue+5溢出为负数。你自己试试吧: Enumerable.Range(0, int.MaxValue) .Select(n => Math.Pow(n, 2)) .Where(squared => squared % 2 !

这段代码将迭代从0到max range的所有整数值,还是只遍历整数值以满足take-while、where和select运算符? 有人能澄清一下吗


编辑:我第一次尝试确保它按预期工作是愚蠢的。我撤销它:)

int.MaxValue+5
溢出为负数。你自己试试吧:

Enumerable.Range(0, int.MaxValue)
          .Select(n => Math.Pow(n, 2))
          .Where(squared => squared % 2 != 0)
          .TakeWhile(squared => squared < 10000).Sum()
Enumerable.Range
的第二个参数必须是非负的-因此是异常

当然,您可以在LINQ中使用无限序列。下面是这样一个序列的示例:

unchecked
{
    int count = int.MaxValue + 5;
    Console.WriteLine(count); // Prints -2147483644
}
public IEnumerable InfinitieCounter()
{
int计数器=0;
while(true)
{
未经检查
{
收益返回计数器;
计数器++;
}
}
}
当然,这也会溢出,但它会继续下去


请注意,某些LINQ运算符(例如,
Reverse
)需要读取所有数据才能产生第一个结果。其他人(如
Select
)可以在从输入读取结果时保持流式处理结果。有关每个运算符的行为的详细信息,请参见my(在LINQ to Objects中)。

只要满足
TakeWhile
条件,您的第一个代码将只进行迭代。在
int.MaxValue
之前,它不会迭代


int.MaxValue+5
将产生一个负整数<如果ArgumentOutOfRangeException的第二个参数为负,则code>Enumerable.Range将抛出ArgumentOutOfRangeException。因此,这就是为什么会出现异常(在任何迭代发生之前)。

解决这类问题的一般方法是分步思考发生了什么

Linq将Linq代码转换为将由查询提供程序执行的代码。这可能类似于生成SQL代码,或者其他所有的事情。对于linq to对象,它会生成一些等效的.NET代码。思考一下.NET代码将是什么,让我们思考一下将会发生什么*

使用您的代码,您可以:

public IEnumerable<int> InfiniteCounter()
{
    int counter = 0;
    while (true)
    {
        unchecked
        {
            yield return counter;
            counter++;
        }
    }
}
…但为了争论,这已经足够接近了

选择距离足够近,可以:

for(int i = start; i != start + count; ++i)
  yield return i;
foreach(T item in source)
  yield return func(item);
foreach(T item in source)
  if(func(item))
    yield return item;
foreach(T item in source)
  if(func(item))
    yield return item;
  else
    yield break;
距离以下位置足够近:

for(int i = start; i != start + count; ++i)
  yield return i;
foreach(T item in source)
  yield return func(item);
foreach(T item in source)
  if(func(item))
    yield return item;
foreach(T item in source)
  if(func(item))
    yield return item;
  else
    yield break;
TakeWhile离以下位置足够近:

for(int i = start; i != start + count; ++i)
  yield return i;
foreach(T item in source)
  yield return func(item);
foreach(T item in source)
  if(func(item))
    yield return item;
foreach(T item in source)
  if(func(item))
    yield return item;
  else
    yield break;
总和接近于:

for(int i = start; i != start + count; ++i)
  yield return i;
foreach(T item in source)
  yield return func(item);
foreach(T item in source)
  if(func(item))
    yield return item;
foreach(T item in source)
  if(func(item))
    yield return item;
  else
    yield break;
这简化了一些优化,等等,但已经足够接近理性了。依次使用这些代码,您的代码相当于:

T tmp = 0;//must be numeric type
foreach(T x in source)
  tmp += x;
return tmp;
List<double> tmpList = new List<double>(); // part of ToList equivalent
for(int i = 0; i != int.MaxValue; ++i) // equivalent of Range
{
  double j = Math.Pow(i, 2);  // equivalent of Select(n => Math.Pow(n, 2))
  if(j % 2 != 0) //equivalent of Where(squared => squared %2 != 0)
  {
    tmpList.Add(j);//part of equivalent to ToList()
  }
}
double ret = 0; // part of equivalent of sum
foreach(double k in tmpList)
{
  if(k < 10000) //equivalent of TakeWhile(squared => squared < 10000)
  {
     ret += k; //equaivalent of Sum()
  }
  else //TakeWhile stopping further iteration
  {
    break;
  }
}
return ret; //end of equivalent of Sum()
理论上,这将给出完全相同的答案,但这样做需要更长、更多的内存(可能足以导致内存不足异常)。但此处等效的非linq代码是:

Enumerable.Range(0, int.MaxValue)
  .Select(n => Math.Pow(n, 2))
  .Where(squared => squared % 2 != 0)
  .ToList()
  .TakeWhile(squared => squared < 10000).Sum()

这将变成对ICollection的
Count
属性或数组的
Length
属性的调用,这意味着上面的O(n)被O(1)(对于大多数ICollection实现)调用所取代,这对于大序列来说是一个巨大的增益。

uhh。。。您超过了整数的最大范围。。。你期望会发生什么?+1用于教育。一套精彩的文章。您在第一篇或第二篇文章中有类似的代码。到Edulinq博客文章的链接现在已断开。您有其他有效的引用吗?似乎
yield
ing over int.maxvalue项会引发异常:我无法理解,我们将否定参数传递给
Enumerable.Range
,有人能解释一下吗?@teenup我相信问题中的代码最初包含表达式
int.MaxValue+5
,但在宽限期内进行了编辑(因此问题中的“编辑”注释)。