给出int
个数字数组,例如:
int[] arr = new int[] { 0, 1, 2, 3, 4, 5 };
如果我们想将每个数字加1,最好的选择是:
for(int i = 0; i < arr.Length; i++)
{
arr[i]++;
}
如果我们尝试使用foreach
foreach(int n in arr)
{
n++;
}
按预期,我们遇到了错误:
由于它是“ foreach迭代变量”,因此无法分配给“ n”
为什么要使用这种方法:
Array.ForEach(arr, (n) => {
n++;
});
与上面的foreach
相等,Visual Studio和编译器不会告诉我们任何信息,代码将进行编译,并且在运行时不会产生任何结果,也不会引发异常? >
答案 0 :(得分:2)
foreach(int n in arr)
{
n++;
}
这是一种语言构造,编译器确切地知道应该执行foreach循环以及执行n
。因此,它可以防止您更改迭代变量n
。
Array.ForEach(arr, (n) => {
n++;
});
这是一个传入lambda的常规函数调用。修改函数(或lambda)中的局部变量是完全有效的,因此可以更改n
。尽管编译器可以提醒您,增量没有作用,因为以后将永远不会使用它,但这是有效的代码,并且仅仅是因为该函数被称为ForEach
并且实际上执行了与foreach类似的操作-loop不会改变这是一个常规函数和常规lambda的事实。
答案 1 :(得分:0)
两者都是两回事。
首先,我们需要弄清楚我们需要什么。如果要求更改现有值,则可以使用for循环,因为在枚举集合时不应修改值,这就是为什么您在第一个foreach循环中会遇到错误。
所以一种方法可能是意图突变:
for(int i=0; i< arr.Length; i++)
{
arr[i] = arr[i] +1;
}
第二,如果要获取具有更新后值的新集合,请考虑使用linq Select
方法,该方法将返回int
的新集合。
var incrementedArray = arr.Select( x=> (x+1));
关键区别在于,在第一个示例中,我们在枚举collecoll的值的同时对其进行了修改,而在lambda语法foreach
中,使用了一个委托作为输入,以作为局部变量。
答案 2 :(得分:0)
foreach
语句为实现System.Collections.IEnumerable
或System.Collections.Generic.IEnumerable<T>
接口的类型的实例中的每个元素执行一个语句或语句块。您无法修改迭代值,因为您正在使用支持延迟执行的System.Collections.IEnumberable
或System.COllections.Generic.IEnumberable<T>
接口。
如果您想修改值,也可以使用
foreach(ref int n in arr)
{
n++;
}
已更新
Array.Foreach
是一种对指定数组的每个元素执行指定操作的方法。此函数支持立即执行行为,并且只能应用于内存中保存的数据。 Array.Foreach
方法采用数组,并使用For
循环遍历集合。
foreach
和Array.Foreach
看上去相同,但工作方式不同。
答案 3 :(得分:0)
正如@tkausl所指出的,n
和ForEach
是局部变量。因此:
static void Main()
{
int[] arr = new int[] { 0, 1, 2, 3, 4, 5 };
Console.WriteLine(string.Join(" ",arr));
Array.ForEach(arr, (n) => {
n++;
});
Console.WriteLine(string.Join(" ",arr));
}
将输出:
0 1 2 3 4 5
0 1 2 3 4 5
表示您不要更改 arr
的值。
答案 4 :(得分:0)
Array.ForEach
与foreach
循环不相同。这是一种扩展方法,它将对集合进行迭代并对其每个元素执行操作。
Array.ForEach(arr, (n) => {
n++;
});
但是不会修改actuzal集合,它只会将一个新值重新分配给n
,该新值与数组中的基础值无关,因为它的值类型是**复制*到匿名方法。因此,对匿名方法中的param所做的任何操作都不会反映到ForEach
方法中,因此在数组中没有任何作用。这就是为什么您可以这样做。
但是,即使您有一个可以使用的引用类型数组,因为您只需将新实例重新分配给所提供的参数,这对基础数组也不起作用。
看看这个简化的例子:
MyClass
{
void ForEach(Action<Item> a)
{
foreach(var e in myList)
Action(e);
}
}
在您的情况下,操作如下所示:
x => x++
只是为x
分配一个新值。然而,由于x
是通过值传递的,因此这对调用方法以及myList
都没有任何影响。