C# IEnumerable IndexOutOfRangeException
我不知道为什么我会得到C# IEnumerable IndexOutOfRangeException,c#,ienumerable,C#,Ienumerable,我不知道为什么我会得到System.IndexOutOfRangeException:“索引超出了数组的界限。”使用此代码 IEnumerable<char> query = "Text result"; string illegals = "abcet"; for (int i = 0; i < illegals.Length; i++) { query = query.Where(c => c != illegals[i]); } foreach (var
System.IndexOutOfRangeException:“索引超出了数组的界限。”
使用此代码
IEnumerable<char> query = "Text result";
string illegals = "abcet";
for (int i = 0; i < illegals.Length; i++)
{
query = query.Where(c => c != illegals[i]);
}
foreach (var item in query)
{
Console.Write(item);
}
IEnumerable query=“文本结果”;
字符串非法者=“abcet”;
for(int i=0;ic!=非法者[i]);
}
foreach(查询中的var项)
{
控制台。写入(项);
}
请有人解释一下我的代码出了什么问题。问题是lambda表达式正在捕获变量
i
,但直到循环结束后才执行委托。当表达式c!=非法者[i]
被执行,i
是illegals.Length
,因为这是i
的最终值。重要的是要理解lambda表达式捕获变量,而不是“lambda表达式转换为委托时这些变量的值”
以下是修复代码的五种方法:
选项1:i的本地副本
将i
的值复制到循环中的局部变量中,以便循环的每次迭代都在lambda表达式中捕获一个新变量。循环的其余执行不会更改该新变量
for (int i = 0; i < illegals.Length; i++)
{
int copy = i;
query = query.Where(c => c != illegals[copy]);
}
选项3:使用foreach循环
此选项仅适用于C#5及更高版本的编译器,因为在C#5中,foreach
的含义发生了变化(更好)
选项4:使用一次,但除外
LINQ提供了一种执行集合排除的方法:Except
。不过,这与前面的选项并不完全相同,因为您只能在输出中获得任何特定字符的单个副本。因此,如果e
不在illegals
中,您将使用上述选项获得“Tex result”的结果,但使用的“Tex rsul”除外。不过,值得了解的是:
// Replace the loop entirely with this
query = query.Except(illegals);
选项5:使用包含一次
您可以使用调用包含的lambda表达式调用其中的一次:
// Replace the loop entirely with this
query = query.Where(c => !illegals.Contains(c));
这是因为,尽管您的for
循环乍一看似乎是正确的,但每次迭代都会捕获传递到Where
的闭包中的索引。闭包最有用的特性之一是它们通过引用捕获,支持各种强大而复杂的技术。然而,在这种情况下,这意味着,当查询在随后的foreach
循环中执行时。索引的增量已超过数组的长度
解决这个问题的最直接的更改是创建一个循环范围的副本,复制索引循环控制变量的当前值,并在闭包中引用它,而不是直接引用循环控制变量
for (int i = 0; i < illegals.Length; i++)
{
char illegal = illegals[i];
query = query.Where(c => c != illegal);
}
例:
最好这样:var query=query.Where(c=>!illegals.Contains(c));用它替换你的循环。@eocron:是的,在看到你的评论之前,我刚刚添加了它作为第五个选项:)
// Replace the loop entirely with this
query = query.Where(c => !illegals.Contains(c));
for (int i = 0; i < illegals.Length; i++)
{
var index = i;
query = query.Where(c => c != illegals[index]);
}
var legals = query.Except(illegals);