List <t> .ForEach - 对象是否为ForEach传递了引用或副本?</t>

时间:2013-09-08 19:44:26

标签: c#

当使用List<T>.ForEach时,是传入的对象,即以下示例中的j通过引用或值传递?

MyList.ForEach( j => {} );

如果我要这样做:

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

这会对j的副本采取行动还是会对原始对象采取行动?

2 个答案:

答案 0 :(得分:9)

根本没有传入对象 - 有T类型的。如果T是引用类型,则该值是引用。该值通过传递值,正常情况下。

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

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

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

根本不会影响列表。

我怀疑你可能对传值和传递引用的工作有点混淆,特别是在C#的上下文中。我有一个article on the topic可能会帮到你。

答案 1 :(得分:1)

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

Jon Skeet已经给出了答案:它是“正常”传递的,即通过值传递,其中是值类型的整个对象本身,而是对象引用类型的“位置”的引用。因此,问题中的示例可能“有效”(假设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这样的方法;这只是为了说明。)