假设我有一个类

public class MyObject
{
   public int SimpleInt{get;set;}
}

我有一个List<MyObject>,我ToList()它,然后改变一个SimpleInt,我的改变会被传播回原来的列表。换句话说,下面这个方法的输出是什么?

public void RunChangeList()
{
  var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
  var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
  var objectList = objects.ToList();
  objectList[0].SimpleInt=5;
  return objects[0].SimpleInt;

}

为什么?

P/S:很抱歉,这似乎是显而易见的。但是我现在没有编译器……


当前回答

从Reflector来源:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return new List<TSource>(source);
}

所以是的,你的原始列表不会被更新(即添加或删除),但引用的对象将。

其他回答

 var objectList = objects.ToList();
  objectList[0].SimpleInt=5;

这也将更新原始对象。新列表将包含对其中包含的对象的引用,就像原始列表一样。您可以更改其中一个元素,更新将反映在另一个元素中。

现在,如果你更新一个列表(添加或删除一个项目),将不会反映在另一个列表。

我认为这相当于问ToList是做深度复制还是浅复制。由于ToList无法克隆MyObject,它必须进行浅拷贝,因此创建的列表包含与原始列表相同的引用,因此代码返回5。

接受的答案根据OP的例子正确地回答了他的问题。但是,它只适用于将ToList应用于具体集合时;当源序列的元素还没有被实例化(由于延迟执行)时,它不会保持。对于后一种情况,每次调用ToList(或枚举序列)时可能会得到一组新的项。

下面是OP代码的改编,以演示这种行为:

public static void RunChangeList()
{
    var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
    var whatInt = ChangeToList(objs);   // whatInt gets 0
}

public static int ChangeToList(IEnumerable<MyObject> objects)
{
    var objectList = objects.ToList();
    objectList.First().SimpleInt = 5;
    return objects.First().SimpleInt;
}

虽然上面的代码可能看起来不自然,但在其他情况下,这种行为可能是一种微妙的错误。请参阅我的另一个示例,了解它导致重复生成任务的情况。

只是偶然发现了这个旧帖子,并想补充我的意见。通常,如果我有疑问,我会快速地在任何对象上使用GetHashCode()方法来检查标识。对于上面的-

    public class MyObject
{
    public int SimpleInt { get; set; }
}


class Program
{

    public static void RunChangeList()
    {
        var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
        Console.WriteLine("objs: {0}", objs.GetHashCode());
        Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
        var whatInt = ChangeToList(objs);
        Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
    }

    public static int ChangeToList(List<MyObject> objects)
    {
        Console.WriteLine("objects: {0}", objects.GetHashCode());
        Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
        var objectList = objects.ToList();
        Console.WriteLine("objectList: {0}", objectList.GetHashCode());
        Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
        objectList[0].SimpleInt = 5;
        return objects[0].SimpleInt;

    }

    private static void Main(string[] args)
    {
        RunChangeList();
        Console.ReadLine();
    }

然后在答录机上回答

obj: 45653674 obj [0]: 41149443 对象:45653674 对象[0]:41149443 objectList: 39785641 objectList [0]: 41149443 whatInt: 5

所以本质上list所携带的对象在上面的代码中保持不变。希望这种方法能有所帮助。

是的,ToList将创建一个新列表,但是因为在这种情况下MyObject是一个引用类型,所以新列表将包含对与原始列表相同对象的引用。

更新新列表中引用的对象的SimpleInt属性也会影响原始列表中的等效对象。

(如果MyObject声明为结构体而不是类,则新列表将包含原始列表中元素的副本,并且更新新列表中元素的属性不会影响原始列表中的等效元素。)