ToList() - 它是否创建新列表?

时间:2010-05-05 14:29:22

标签: c# linq

假设我有一个班级

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:如果发现这一点似乎很明显,我很抱歉。但我现在没有编译器......

12 个答案:

答案 0 :(得分:192)

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

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

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

答案 1 :(得分:58)

来自Reflector'd来源:

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

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

答案 2 :(得分:30)

ToList将始终创建一个新列表,该列表不会反映对集合的任何后续更改。

但是,它会反映对象本身的变化(除非它们是可变的结构)。

换句话说,如果使用其他对象替换原始列表中的对象,ToList仍将包含第一个对象。
但是,如果您修改原始列表中的一个对象,ToList仍将包含相同(已修改)的对象。

答案 3 :(得分:11)

是的,它会创建一个新列表。这是设计的。

该列表将包含与原始可枚举序列相同的结果,但具体化为持久性(内存中)集合。这允许您多次使用结果,而不会产生重新计算序列的成本。

LINQ序列的优点在于它们是可组合的。通常,您获得的IEnumerable<T>是组合多个过滤,排序和/或投影操作的结果。像ToList()ToArray()这样的扩展方法允许您将计算的序列转换为标准集合。

答案 4 :(得分:11)

根据他的例子,接受的答案正确地解决了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;
}

虽然上面的代码可能看似人为,但这种行为在其他场景中可能会出现一个微妙的错误。请参阅my other example,了解导致任务重复生成的情况。

答案 5 :(得分:6)

创建一个新列表,但其中的项目是对原始项目的引用(就像在原始列表中一样)。对列表本身的更改是独立的,但对于项目将在两个列表中找到更改。

答案 6 :(得分:5)

偶然发现这个旧帖子并想到加我的两分钱。通常,如果我有疑问,我会在任何对象上快速使用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();
    }

在我的机器上回答 -

  • objs:45653674
  • objs [0]:41149443
  • 对象:45653674
  • objects [0]:41149443
  • objectList:39785641
  • objectList [0]:41149443
  • whatInt:5

基本上,列表中携带的对象在上面的代码中保持不变。希望这种方法有所帮助。

答案 7 :(得分:4)

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

答案 8 :(得分:2)

ToList将创建一个全新的列表。

如果列表中的项目是值类型,它们将直接更新,如果它们是引用类型,任何更改都将反映在引用的对象中。

答案 9 :(得分:2)

如果源对象是真正的IEnumerable(即不仅仅是一个打包为可枚举的集合),ToList()可能不会返回与原始IEnumerable中相同的对象引用。它将返回一个新的对象列表,但这些对象可能与IEnumerable再次枚举时产生的对象不同或甚至相等

答案 10 :(得分:1)

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

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

现在,如果您更新列表(添加或删除项目),则不会反映在其他列表中。

答案 11 :(得分:1)

我没有在文档中看到ToList()始终保证返回新列表。如果IEnumerable是List,则检查它并返回相同的List可能更有效。

担心的是,有时您可能希望绝对确定返回的List是!=原始列表。因为Microsoft没有记录ToList会返回一个新的List,我们无法确定(除非有人发现该文档)。即使它现在有效,它也可能在未来发生变化。

新列表(IEnumerable enumerablestuff)保证返回新的List。我会改用它。

相关问题