[英]LINQ's deferred execution, but how?
这一定非常简单。 但无论如何我会问它,因为我认为其他人也会挣扎。 为什么以下简单的LINQ查询不会始终使用新的变量值而不是始终使用第一个?
static void Main(string[] args)
{
Console.WriteLine("Enter something:");
string input = Console.ReadLine(); // for example ABC123
var digits = input.Where(Char.IsDigit); // 123
while (digits.Any())
{
Console.WriteLine("Enter a string which doesn't contain digits");
input = Console.ReadLine(); // for example ABC
}
Console.WriteLine("Bye");
Console.ReadLine();
}
在注释的示例中,它将进入循环,因为输入ABC123
包含数字。 但即使你输入类似ABC
东西也不会离开它,因为digits
仍然是123
。
那么为什么LINQ查询不会评估新的input
值 - 但总是第一个?
我知道我可以通过这个附加线修复它:
while (digits.Any())
{
Console.WriteLine("Enter a string which doesn't contain digits");
input = Console.ReadLine();
digits = input.Where(Char.IsDigit); // now it works as expected
}
或 - 更优雅 - 直接在循环中使用查询:
while (input.Any(Char.IsDigit))
{
// ...
}
区别在于您正在更改input
变量的值,而不是变量引用的对象的内容 ...因此digits
仍然引用原始集合。
与此代码比较:
List<char> input = new List<char>(Console.ReadLine());
var digits = input.Where(Char.IsDigit); // 123
while (digits.Any())
{
Console.WriteLine("Enter a string which doesn't contain digits");
input.Clear();
input.AddRange(Console.ReadLine());
}
这一次,我们正在修改input
引用的集合的内容 - 并且由于digits
实际上是对该集合的视图,因此我们可以看到更改。
您正在为input
分配新值,但digits
序列仍然是从input
的初始值派生的。 换句话说,当你执行digits = input.Where(Char.IsDigit)
, 它会捕获 input
变量的当前值 ,而不是变量本身。 为input
分配新值对digits
没有影响。
这一行:
input.Where(Char.IsDigit)
相当于:
Enumerable.Where(input, Char.IsDigit)
因此, input
的值作为.Where
查询的源传递,而不是对input
的引用 。
您建议的第一个修复工作是因为它使用先前行上新input
值。
枚举中的数字指的是字符串的副本input
包含在创建枚举。 它不包含对input
变量的引用,并且更改存储在input
的值不会导致可枚举的实现使用新值。
请记住, Where
是静态扩展方法,并接受您将其作为参数调用的对象。
这几乎是一个评论,但包含结构化代码,所以我提交它作为答案。
以下对代码的轻微修改将起作用:
Console.WriteLine("Enter something:");
string input = Console.ReadLine(); // for example ABC123
Func<bool> anyDigits = () => input.Any(Char.IsDigit); // will capture 'input' as a field
while (anyDigits())
{
Console.WriteLine("Enter a string which doesn't contain digits");
input = Console.ReadLine(); // for example ABC
}
Console.WriteLine("Bye");
Console.ReadLine();
这里input
由Func<bool>
类型的委托捕获(闭包)。
我正在回答只是为其他好的答案添加精度,关于延迟执行 。
即使尚未评估LINQ查询(使用.Any()
),查询内部也总是引用变量的初始内容 。 即使在对变量影响了新内容之后评估LINQ查询,初始内容也不会更改,延迟执行将使用查询一直引用的初始内容:
var input = "ABC123";
var digits = input.Where(Char.IsDigit);
input = "NO DIGIT";
var result = digits.ToList(); // 3 items
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.