public class TestClass
{
public int Num { get; set; }
public string Name { get; set; }
}
IEnumerable<TestClass> originalEnumerable
= Enumerable.Range(1, 1).
Select(x => new TestClass() { Num = x, Name = x.ToString() });
List<TestClass> listFromEnumerable = originalEnumerable.ToList();
// false
bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable.ElementAt(0));
如果我修改复制的对象,原件不会改变。
我从中理解,System.Linq.IEnumerable<T>
集合总是会产生新对象,即使它们在调用ToList()
/ ToArray()
时是引用类型?我错过了一些东西,因为其他SO问题坚持只有复制参考。
答案 0 :(得分:11)
实际上,这是错误的原因是因为你的枚举实际上被枚举了两次,一次是在调用originalEnumerable.ToList()
中,第二次是在你调用originalEnumerable.ElementAt(0)
时。< / p>
由于它枚举了两次,因此每次枚举时都会创建新对象。
答案 1 :(得分:7)
你错过了Enumerable.Range
是懒惰的事实,所以这一行实际上只产生了内存中的查询定义:
IEnumerable<TestClass> originalEnumerable
= Enumerable.Range(1, 1).
Select(x => new TestClass() { Num = x, Name = x.ToString() });
调用ToList()
会触发查询并创建包含新项目的列表:
List<TestClass> listFromEnumerable = originalEnumerable.ToList();
在此处拨打originalEnumerable.ElementAt(0)
bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable.ElementAt(0));
再次触发查询,并生成另一个新项目。
更新
所以你应该说,Enumerable.Range
产生新项目,而不是ToList()
。
如果您的源集合已经过评估(例如TestClass[]
数组)ToList()
将无法创建新项:
IEnumerable<TestClass> originalEnumerable
= Enumerable.Range(1, 1).
Select(x => new TestClass() { Num = x, Name = x.ToString() })
.ToArray();
List<TestClass> listFromEnumerable = originalEnumerable.ToList();
// true
bool test = ReferenceEquals(listFromEnumerable[0], originalEnumerable[0]);