为啥有时 IEnumerable<T> 中的元素是可变的,而有时它们是不可变的? [复制]
Posted
技术标签:
【中文标题】为啥有时 IEnumerable<T> 中的元素是可变的,而有时它们是不可变的? [复制]【英文标题】:Why sometime elements in an IEnumerable<T> are mutable and sometime they are immutable? [duplicate]为什么有时 IEnumerable<T> 中的元素是可变的,而有时它们是不可变的? [复制] 【发布时间】:2020-11-25 14:23:41 【问题描述】:假设我有一个非常简单的引用类型,称为Person
。
class Person
public string Name get; set;
public int Age get; set;
我使用 LINQ 创建一个 IEnumerable 调用 peopleEnum
,代码如下。
var ages = new int[] 1, 2, 3, 4, 5 ;
var peopleEnum = ages.Where(a => a > 1)
.Select(a => new Person
Name = a.ToString(),
Age = a
);
我的理解是因为Person
是引用类型,所以peopleEnum
里面的元素应该是可变的。但我发现他们不是。
var person = peopleEnum.Single(p => p.Age == 4);
person.Name = "Four";
foreach (var p in peopleEnum)
Console.WriteLine($"p.Name, p.Age");
预期输出。
2, 2
3, 3
Four, 4
5, 5
实际输出。
2, 2
3, 3
4, 4
5, 5
但是,如果我以不同的方式创建 IEnumerable<Person>
。
var people = new Person[]
new Person Name = "1", Age = 1 ,
new Person Name = "2", Age = 2 ,
new Person Name = "3", Age = 3 ,
new Person Name = "4", Age = 4 ,
new Person Name = "5", Age = 5 ,
;
var peopleEnum2 = people.Where(p => p.Age > 1);
那么peopleEnum2
中的元素将是可变的。
var person = peopleEnum2.Single(p => p.Age == 4);
person.Name = "Four";
foreach (var p in peopleEnum2)
Console.WriteLine($"p.Name, p.Age");
输出
2, 2
3, 3
Four, 4
5, 5
哪些规则确定IEnumerable<T>
中的元素是否可变?
【问题讨论】:
在您的示例中,您枚举了IEnumerable<T>
两次。当IEnumerable<T>
是一个具体的列表或数组时,多次枚举每次都会产生相同的元素。在您的第一个示例中,每次枚举时都会“动态”和“按需”创建元素,这就是为什么每次都会获得不同的元素。
当您执行Single
时,它会运行创建人员对象的代码。然后,当您运行 foreach
时,它会再次运行该代码,创建 4 个新对象。这称为延迟执行。
【参考方案1】:
有区别 - 这个IEnumerable
基于ages
数组,每次枚举peopleEnum
时都会执行。这意味着每次将枚举放入 foreach
语句时都会获得新的引用。
var ages = new int[] 1, 2, 3, 4, 5 ;
var peopleEnum = ages.Where(a => a > 1)
.Select(a => new Person
Name = a.ToString(),
Age = a
);
为了使元素在第一种情况下“可变”,您必须将结果存储到某个静态结构中。例如,使用.ToList()
。这有助于确保您只执行一次 Select
语句并保留由它生成的引用
var peopleEnum = ages.Where(a => a > 1)
.Select(a => new Person
Name = a.ToString(),
Age = a
).ToList();
【讨论】:
【参考方案2】:这是因为每次迭代peopleEnum
枚举,
var peopleEnum = ages.Where(a => a > 1)
.Select(a => new Person
Name = a.ToString(),
Age = a
);
创建了一个新的Person
。使用数组时,它们被创建一次(并放入数组中)。
因此,在您的情况下,您对其进行迭代并更改人员。当你再次迭代它时,就会创建一个新人。
【讨论】:
以上是关于为啥有时 IEnumerable<T> 中的元素是可变的,而有时它们是不可变的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Enumerable 不实现 IEnumerable?
将 IEnumerable<Ienumerable<T>> 转换为 Dictionary<key,IEnumerable<T>>
为啥 HashSet<T> 没有实现 ICollection?
为啥我不能将 List<List<Foo>> 传递给 IEnumerable<IEnumerable<Foo>>