C# 为什么有时在IEnumerable中包含元素<;T>;是可变的,有时是不变的?
假设我有一个非常简单的引用类型,名为C# 为什么有时在IEnumerable中包含元素<;T>;是可变的,有时是不变的?,c#,linq,immutability,ienumerable,C#,Linq,Immutability,Ienumerable,假设我有一个非常简单的引用类型,名为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
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
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
中的元素是否可变?这是因为每次迭代peopleEnum
enum时
var peopleEnum = ages.Where(a => a > 1)
.Select(a => new Person
{
Name = a.ToString(),
Age = a
});
将创建一个新的人员
。使用数组时,它们只创建一次(并放入数组)。
所以在你的例子中,你迭代它并改变人物。当您再次迭代它时,会创建一个新的人物。有区别-此
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();
在示例中,您将枚举
IEnumerable
两次。如果IEnumerable
是一个具体的列表或数组,那么多次枚举每次都会产生相同的元素。在第一个示例中,每次枚举时都会“动态”和“按需”创建元素,这就是为什么每次都会得到不同的元素。当您执行Single
时,它会运行创建人员对象的代码。然后,当您运行foreach
时,它会再次运行该代码,创建4个新对象。这称为差异执行。