【问题标题】:List<T>.ForEach - Is the object passed into ForEach a reference or a copy?List<T>.ForEach - 传递给 ForEach 的对象是引用还是副本?
【发布时间】:2013-09-08 19:44:26
【问题描述】:

当使用List&lt;T&gt;.ForEach 时,是传入的对象,即下例中的j,是通过引用还是通过值传递?

MyList.ForEach( j => {} );

如果我要这样做:

MyList.ForEach( j => {
    j.someOtherList.Add("value");
});

这是作用于j 的副本还是作用于原始对象?

【问题讨论】:

  • 视情况而定。 j 是引用类型还是值类型的实例?
  • 这是一个 reference,但您不能将 reference 分配给另一个,但是因为它是 reference,您可以更改/修改对象的所有属性。
  • @FrédéricHamidi:这并不取决于:值是通过 按值 传递的……但该值可能是引用(绝不是对象)。
  • @Jon,是的,即使值是引用,值也是按值传递的 :) 当我发表我的第一条评论时,我更关注j 作为实例之间的可能差异值或引用类型,特别是如果 someOtherList 本身就是引用类型的实例。

标签: c#


【解决方案1】:

根本没有传入一个对象 - 有一个T 类型的。如果T 是引用类型,则该值是引用。该值是通过 值传递的,就像平常一样。

现在假设T 是一些引用类型,其成员名为someOtherList,那么您的代码确实会影响j 的值所指的对象 - 但@ 的值987654327@ 只是一个参考。列表中的值将是 same 引用,因此如果您随后(例如)再次遍历列表,您将能够看到效果。

重要的是,如果您将代码更改为:

MyList.ForEach( j => {
    j = new WhateverYourTypeIs()
});

不会影响列表。

我怀疑您可能对按值传递和按引用传递的工作方式有些困惑,尤其是在 C# 上下文中。我有一个article on the topic 可以帮助你。

【讨论】:

  • 抱歉,我的术语不正确。但是谢谢你把这件事弄清楚,乔恩。有道理。
【解决方案2】:

这是一种评论(太长,无法放入评论字段)。

Jon Skeet 已经给出了答案:它是“正常”传递的,即按值传递,其中 value 是值类型的整个对象本身,而 value em> 是对引用类型的对象“位置”的引用。所以问题中的示例很可能“工作”(假设someOtherListj 类型的引用类型成员)。

但只是为了好玩,我写了一个替代ForEachByRef,它是by-ref:

public delegate void ActionByRef<J>(ref J j);

public static class MyExtensions
{
    public static void ForEachByRef<T>(this List<T> list, ActionByRef<T> action)
    {
        for (int i = 0; i < list.Count; ++i)
        {
            T t = list[i];
            action(ref t);
            list[i] = t;
        }
    }
}

然后这个工作:

static void Main()
{
    var testList = new List<string> { "alpha", "bravo", "charlie", };
    testList.ForEachByRef((ref string j) => { j = "changed"; });
}

(我不建议在“真实”代码中实际使用ForEachByRef 之类的方法;这只是为了说明。)

【讨论】:

  • 我非常感谢评论所付出的努力。很遗憾我不能接受两个答案。谢谢。
猜你喜欢
  • 2014-06-22
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
  • 2012-11-27
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多