IEnumerable T和.Linq方法的行为在哪里? [英] IEnumerable<T> and .Where Linq method behaviour?

查看:85
本文介绍了IEnumerable T和.Linq方法的行为在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以为我了解IEnumerable<T>的所有知识,但是我遇到了一个我无法解释的情况.当我们调用IEnumerable上的linq方法时,执行将推迟到枚举该对象之前,是吧?

I thought I know everything about IEnumerable<T> but I just met a case that I cannot explain. When we call .Where linq method on a IEnumerable, the execution is deferred until the object is enumerated, isn't it?

那么如何解释以下示例:

So how to explain the sample below :

public class CTest
{
    public CTest(int amount)
    {
        Amount = amount;
    }

    public int Amount { get; set; }

    public override string ToString()
    {
        return $"Amount:{Amount}";
    }

    public static IEnumerable<CTest> GenerateEnumerableTest()
    {
        var tab = new List<int> { 2, 5, 10, 12 };

        return tab.Select(t => new CTest(t));
    }
}

到目前为止,还不错! 但是,尽管我对IEnumerable<T>.Where linq方法的了解,以下测试仍给我带来了意外的结果:

Nothing bad so far! But the following test gives me an unexpected result although my knowledge regarding IEnumerable<T> and .Where linq method :

[TestMethod]
public void TestCSharp()
{
    var tab = CTest.GenerateEnumerableTest();

    foreach (var item in tab.Where(i => i.Amount > 6))
    {
        item.Amount = item.Amount * 2;
    }

    foreach (var t in tab)
    {
        var s = t.ToString();
        Debug.Print(s);
    }
}

选项卡中的任何项目都不会乘以2.输出将是: 数量:2 数量:5 数量:10 数量:12

No item from tab will be multiplied by 2. The output will be : Amount:2 Amount:5 Amount:10 Amount:12

任何人都可以解释为什么在枚举制表符后获得原始值. 当然,在调用GenerateEnumerableTest()方法之后,在调用.ToList()后一切正常.

Does anyone can explain why after enumerating tab, I get the original value. Of course, everything work fine after calling .ToList() just after calling GenerateEnumerableTest() method.

推荐答案

var tab = CTest.GenerateEnumerableTest();

tab是LINQ查询,它生成从int值初始化的CTest实例,这些值来自永远不会改变的整数数组.因此,每当您请求此查询时,您都将获得相同"实例(具有原始的Amount).

This tab is a LINQ query that generates CTest instances that are initialized from int-values which come from an integer array which will never change. So whenever you ask for this query you will get the "same" instances(with the original Amount).

如果要具体化"此查询,可以使用ToList,然后进行更改. 否则,您将修改仅在第一个foreach循环中存在的CTest实例.第二个循环枚举具有未修改的Amount的其他CTest实例.

If you want to "materialize" this query you could use ToList and then change them. Otherwise you are modifying CTest instances that exist only in the first foreach loop. The second loop enumerates other CTest instances with the unmodified Amount.

因此查询包含如何获取商品的信息,您也可以直接调用该方法:

So the query contains the informations how to get the items, you could also call the method directly:

foreach (var item in CTest.GenerateEnumerableTest().Where(i => i.Amount > 6))
{
    item.Amount = item.Amount * 2;
}

foreach (var t in CTest.GenerateEnumerableTest())
{
   // now you don't expect them to be changed, do you?
}

这篇关于IEnumerable T和.Linq方法的行为在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆