[英]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.