c# - 更新 ForEach 循环内的变量

标签 c# linq .net-4.0

我根本无法理解为什么这个简单的代码不起作用。我的预期输出是 10 和 15,但返回的是 2 和 3。这意味着更新不起作用。

List<int> numbers = new List<int>();

numbers.Add(2);
numbers.Add(3);

numbers.ForEach(n => n = n*5);

numbers.ForEach(n => Console.WriteLine(n));


注意:我已经搜索了很多,但我无法理解这种行为。

我该如何解决?

更新:字符串的行为相同。

List<string> strings = new List<string>();
strings.Add("a");
strings.Add("b");

strings.ForEach(s => s = s + "--");

strings.ForEach(s => Console.WriteLine(s));

最佳答案

n是列表中当前值的副本,而不是对值的引用。如果要操作列表中的值,请使用 for 循环

for(int i = 0; i<numbers.Count; i++)
    numbers[i] *= 5;

更详细的解释:

正常foreach循环您的代码甚至无法编译:

foreach(var n in numbers)
      n = n * 5; // Readonly local variable cannot be used as an assignment target

记住 List<T>.ForEach loop 与 foreach 不同但它只是一种采用 Action<int> 的方法委托(delegate)作为参数并对列表中的每个元素执行指定的操作。因此它执行如下操作(取自源代码):

 public void ForEach(Action<T> action) 
 {
     // removed unnecessary parts for brevity
     for(int i = 0 ; i < _size; i++) 
     {
         action(_items[i]);
     }
 } 

正如您在这里看到的 _item[i]传递给操作,因为 int 是值类型,所以传递的是值的副本而不是引用。这就是为什么你的值没有改变。

对于字符串:除了字符串不可变这一事实之外,将新引用分配给引用类型不会更改持有相同引用的对象。例如考虑以下内容:

static void Update(string s)
{
     s = "bar";
}

string f = "foo";
Update(f);
Console.WriteLine(f); // foo

s 分配新的引用不会改变 f , f stil 持有旧引用和 s指向内存中的新位置。这不是因为 s是副本,不是。如果您更改 s 的属性(对于字符串你不能这样做,但尝试使用另一种引用类型),它会更新 f 的属性。也。它以这种方式工作,因为sf是两个不同的字符串,指向内存中的相同位置。所以 s未绑定(bind) f .你可以认为它们是这样声明的:

string f = "foo";
string s = f;
s  = "bar";

唯一的异常(exception)是当您通过 f 时作为ref论证那么分配将改变f还有:

static void Update(ref string s)
{
     s = "bar";
}

string f = "foo";
Update(ref f);
Console.WriteLine(f); // bar

关于c# - 更新 ForEach 循环内的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26049664/

相关文章:

c# - T4 模板 If Else 语句写出对象而不是文本?

C# 异步等待澄清?

linq - 如何使用 lambda 表达式过滤对象列表?

c# - Visual Studio 中的 WriteLine 就像在 LinqPad 中一样

.net - 在 NETFX 4.0 工具之外运行 sn.exe 出现问题

.net-4.0 - PROMOTE TRANSACTION 请求失败,因为没有事件的本地事务

c# - 是否可以在 Parallel.For 中定义执行顺序?

c# - 使用 Rx 缓存来自 Web 服务的结果并在 C# UWP 应用程序中本地使用

c# - 处理对象时避免重复编码

linq - Linq `Where` 子句查询结果是否可以根据查询是延迟执行还是非延迟执行而有所不同?