c# - IEnumerable和。Linq 方法的行为在哪里?
问题描述
我以为我什么都知道,IEnumerable<T>
但我只是遇到了一个我无法解释的案例。当我们在 a 上调用 .Where linq 方法时IEnumerable
,执行会延迟到枚举对象为止,不是吗?
那么如何解释下面的示例:
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 方法:
[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。输出将是: Amount:2 Amount:5 Amount:10 Amount:12
有谁可以解释为什么在枚举选项卡后,我得到了原始值。
当然,.ToList()
在调用GenerateEnumerableTest()
方法之后调用一切正常。
解决方案
var tab = CTest.GenerateEnumerableTest();
这tab
是一个 LINQ 查询,它生成的CTest
实例从int
-value 初始化,这些 -values 来自一个永远不会改变的整数数组。因此,每当您要求此查询时,您都会得到“相同”的实例(与原始实例Amount
)。
如果您想“实现”此查询,您可以使用ToList
然后更改它们。否则,您正在修改CTest
仅存在于第一个foreach
循环中的实例。第二个循环CTest
使用未修改的 枚举其他实例Amount
。
因此查询包含如何获取项目的信息,您也可以直接调用该方法:
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?
}
推荐阅读
- nginx - 将位置添加为位置块内的 add_header
- c# - 为什么csv文件在C#中不显示特殊字符?
- python - 如何在python中设置protobuf字段或属性
- haskell - Haskell + Persistent:解析错误可能缩进不正确或括号不匹配
- html - 如何在动态创建的按钮中添加字体真棒图标
- swift - IntentHandler 无法读取 UserDefaults 但 Timeline 可以
- python - 如何向 pyspark 数据框添加排名
- angular - ag-grid buttonrenderer 每个按钮的非静态标签
- linux - 为什么 rsync 会创建 ~ 文件?
- spring-boot - 使用 Spring Security OAuth Principal 调用 Youtube API