Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么有时在IEnumerable中包含元素<;T>;是可变的,有时是不变的?_C#_Linq_Immutability_Ienumerable - Fatal编程技术网

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个新对象。这称为差异执行。