解决修改IEnumerable<>不成功的问题
我使用ExcelMapper读取了一个Excel,得到
var excelData = new ExcelMapper(workbook) { HeaderRow = false, MinRowNumber = 2 }
.Fetch<UsersExcelModel>().Select((p, i) => { p.RowNo = i + 3; return p; });
之后,修改excelData的内容
foreach (var item in excelData)
{
item.UserStatus= UserStatus.OnLine;
}
让我费解现象出现了:在foreach中修改枚举UserStatus的值成功,但出了循环,excelData里的UserStatus枚举值还是老样子。
class列表是引用类型,不是值类型,我只是修改引用类型属性的值,又不是修改它的引用,怎么会这样?
一番苦找,最终确定,这是IEnumerable<>的延迟执行的特性所导致的。
因为ExcelMapperFetch返回的是IEnumerable<>类型,而IEnumerable<>自带延迟执行。每次遍历IEnumerable<>,查询都会重新执行。如果底层数据源(如数据库上下文、一个每次返回新实例的工厂方法)在两次遍历之间发生了变化,或者查询本身会生成新对象(例如使用了 Select投影),那么第二次遍历到的对象,很可能已经不是第一次遍历时修改的那个对象了。这就造成了“循环内修改有效,循环外看似无效”的假象。
解决方案:在excelData后增加.ToList(),让结果立刻加载“固化”到内存中,阻止其延迟执行。
var excelData= new ExcelMapper(workbook) { HeaderRow = false, MinRowNumber = 2 }
.Fetch<UsersExcelModel>().Select((p, i) => { p.RowNo = i + 3; return p; }).ToList();
代码的最大的问题,是在Fetch后面,用了Select,如果不使用.ToList()或.ToArray()“固化”下来,且没有在后面调用任何会触发其执行的方法,赋值操作就永远不会发生。这完美解释了“循环内看着正常,循环外无效”的现象,因为循环内触发了执行,在循环之外使用excelData时又触发的一次,产生的两个列表是完全不同的,所以修改不会生效。

浙公网安备 33010602011771号