捕获的变量IndexOutOfBounds

时间:2019-12-08 20:24:29

标签: c# string linq ienumerable

我有两个代码循环的代码片段,后者按预期工作,而前者抛出异常。为什么foreach工作而for循环不工作?到底是什么原因?

IEnumerable<char> query = "Not what you might expect";

query = query.Where (c => c != 'a');
query = query.Where (c => c != 'e');
query = query.Where (c => c != 'i');
query = query.Where (c => c != 'o');
query = query.Where (c => c != 'u');

foreach (char c in query) Console.Write (c);  // Nt wht y mght xpct

有异常的循环

IEnumerable<char> query = "Not what you might expect";
string vowels = "aeiou";

for (int i = 0; i < vowels.Length; i++)
  query = query.Where (c => c != vowels[i]);

foreach (char c in query) Console.Write (c);

foreach代码,

foreach (char vowel in vowels)
  query = query.Where (c => c != vowel);

foreach (char c in query) Console.Write (c);

2 个答案:

答案 0 :(得分:2)

好吧, Linq 使用 lazy (延迟执行),所以您有:

// Just a declaration, query doesn't execute
for (int i = 0; i < vowels.Length; i++)
  query = query.Where (c => c != vowels[i]);

// now, after the for loop, i is equal to vowels.Length

// Here, query executes with current i value, i == vowels.Length
// And you have an out of range exception
foreach (char c in query) Console.Write (c);

答案 1 :(得分:1)

for循环捕获i变量,为避免这种情况,您必须编写类似的内容

for (int i = 0; i < vowels.Length; i++)
{
    int index = i;
    query = query.Where(c => c != vowels[index]);
}

否则,在此行的查询执行期间

foreach (char c in query) Console.Write (c);

捕获的i变量的值将等于vowels.Length,并导致索引超出范围异常。发生这种情况是因为documentation

使用Linq使用了延迟执行
  

立即返回值是一个存储所有   执行操作所需的信息。查询   直到对象为   通过直接调用其GetEnumerator方法或通过枚举来枚举   在Visual C#中使用foreach

在您的情况下,直接返回值为Linq查询,该查询捕获循环变量i。创建查询后(在其内部调用foreach方法的情况下,在GetEnumerator循环中遍历对象时会枚举对象。在执行过程中,查询使用捕获的等于5的循环变量。

foreach片段中没有捕获到的循环变量,它工作正常

foreach (char vowel in vowels)
    query = query.Where (c => c != vowel);