簡體   English   中英

LINQ的延期執行,但如何?

[英]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();

這里inputFunc<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM