在 .net-core 中使用 linq 语句时,IEnumerable 和 List 之间出现意外差异?

28 浏览
0 Comments

在 .net-core 中使用 linq 语句时,IEnumerable 和 List 之间出现意外差异?

这个问题已经有答案了

IEnumerable和List - 该使用哪个?它们怎么工作?

IEnumerable和Array、IList和List之间的区别是什么?

List、IList和IEnumerable之间的比较

当我在Select()语句的末尾添加.ToList()时,它的效果与预期相符。

在这种情况下,IEnumerable和List有什么区别?

class Foo{
    public string Name { get; set; }
    public Guid Id { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        var list = new List(){ "first", "last" };
        var bar = list.Select(x => new Foo {
            Name = x,
            Id = Guid.NewGuid()
        }); //.ToList();
        Console.WriteLine("bar Count = " + bar.Count());
        Console.WriteLine();
        for (int i = 0; i < 3; i++) { 
            Console.WriteLine(bar.First().Name + " " + bar.First().Id);
            Console.WriteLine(bar.Last().Name + " " + bar.Last().Id);
            Console.WriteLine();
        }
    }
}

结果:

examples Count = 2

first 1fabd003-340c-44a4-81ca-1908f206ccdb

last 213f40c9-0705-4676-ad1f-73de21c5bc62

first 9bc117e5-1f10-4855-af95-46258b39955c

last cd787227-12d9-4e25-88bc-634369d85671

first c787e081-8dd3-475c-bf24-44e5f103ed3a

last 7a72080d-2dee-47b1-a55d-af0a7665d0ea

带有.ToList()的结果

bar Count = 2

first 3c1d4f1d-eecd-438a-86a4-e7db0680cad3

last cba1867d-d246-477e-b938-0f9cce457a5c

first 3c1d4f1d-eecd-438a-86a4-e7db0680cad3

last cba1867d-d246-477e-b938-0f9cce457a5c

first 3c1d4f1d-eecd-438a-86a4-e7db0680cad3

last cba1867d-d246-477e-b938-0f9cce457a5c

admin 更改状态以发布 2023年5月21日
0
0 Comments

System.Linq使用延迟执行。当您使用IEnumerable时,每次迭代可枚举对象时,新的Foo值都会生成,并具有每个实例的新Id值。当您调用First()Last()时,您会获得具有不同Guid值的新实例。

当使用ToList()时,Linq表达式立即计算,Foo实例在集合中保持不变,同时Id值已计算好。您的循环遍历具有相同值的集合,First()Last()在每个for循环迭代中返回相同的实例。因此,您每次都会得到相同的Guid值。

您可以在Id属性设置器中设置断点,以查看在IEnumerableList情况下该值被设置了多少次。

0
0 Comments

使用Select时,您正在定义惰性枚举,这意味着您正在定义如何生成可枚举值的规则,但实际上还没有生成值本身。惰性枚举 (又名“延迟加载”) 只是蓝图,没有数据并且不执行任何代码。

因此,当您调用bar.First()bar.Last()时,您正在触发枚举开始生成一些值。每次这样做,它将生成全新的值。这意味着每次您在bar上调用某些操作时,它都将通过新的Guid.NewGuid()调用生成新的值,自然会导致每次生成新的GUID。

然而,如果您在可枚举对象上调用ToList(),则会生成可枚举对象中的值,然后将它们缓存到List中。现在,当您调用bar.First()bar.Last()时,您正在引用List中第一个和最后一个元素的静态值,这些值不会改变。

0