// Person 类 internalclassPerson { publicstring Name { get; set; } = "defaultName"; publicPerson(string name) { Name = name; Console.WriteLine("create a new person: "); }
publicvoidShowSelf() { Console.WriteLine($"My name is {Name}"); } }
使用代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 使用 Select 生成 IEnumerable<Person> IEnumerable<Person> list = new List<string>(){ "ZhangSan","LiSi","WangWu" }.Select(x => new Person(x));
var firstPerson = list.First(); Console.WriteLine(); Console.WriteLine($"I am the first person, my name was changed from {firstPerson.Name} to ZhangSanPro"); firstPerson.Name = "ZhangSanPro"; firstPerson.ShowSelf();
Console.WriteLine(); Console.WriteLine("persons in list:"); foreach (var person in list) { person.ShowSelf(); } Console.ReadKey();
结果:
1 2 3 4 5 6 7 8 9 10 11 12
create a new person:
I am the first person, my name was changed from ZhangSan to ZhangSanPro My name is ZhangSanPro
persons in list: create a new person: create a new person: create a new person: My name is ZhangSan My name is LiSi My name is WangWu
从输出可以看到,对第一个对象的 Name
修改是生效,但是为什么后面转换成 List
后,它的值却没改变呢,按道理修改引用对象的字段,也会影响到
List 中的对象的。
原因分析
在上述代码中,Select 方法返回的是一个
IEnumerable<Person>,这是一个延迟执行的查询,意味着查询的结果(也就是
Person
对象的集合)直到第一次遍历它时才会被计算。因此,当修改
firstPerson 的 Name 属性后,再次遍历
list 时,Select 查询会再次执行,从而创建新的
Person 对象,这就是为什么看到的 Name
属性没有被修改。
因为了为保证修改的对象与遍历的对象是一致的,可以将其转换成
List,再执行后续操作
1 2 3
IEnumerable<Person> list = new List<string>(){ "ZhangSan","LiSi","WangWu" }.Select(x => new Person(x)).ToList();
.ToList() 会在调用时将所有的 Person
马上实例化,这样在修改 firstPerson 的 Name
属性后,list 中的第一个元素的 Name 才会相应的修改。