如何控制IEnumerable的更新?附StructureSchedule方法代码咨询
首先得明确:IEnumerable<T>本质上只是一个迭代契约——它只定义了如何遍历元素,本身并没有提供直接的添加、修改、删除元素的方法。要控制它的"更新"逻辑,核心是掌控背后的数据源,或者通过不同的集合实现、迭代策略来满足你的需求。结合你给出的StructureSchedule方法代码,我来拆解几种实用的控制方式:
1. 用可修改集合作为底层载体(你的代码已经在这么做了)
你在方法里初始化了List<ScheduleDetailsView>作为中间存储,这是非常务实的选择。因为List<T>既实现了IEnumerable<T>,又提供了Add、Remove、直接修改元素等完整的更新方法。
比如你可以继续完善循环逻辑,把生成的ScheduleDetailsView实例逐个添加到scheduleDetailsViews里,最后直接返回这个List:
public IEnumerable<ScheduleDetailsView> StructureSchedule() { bool isStartWeek = false; int index = -1; var week = Enum.GetValues(typeof(Week)).Cast<Week>(); var weekLength = Enum.GetNames(typeof(Week)).Length; List<ScheduleDetailsView> scheduleDetailsViews = new List<ScheduleDetailsView>(); for (int i = 0; i < weekLength; i++) { if (isStartWeek) { if (WorkingGroup.WeekStart == week.ElementAt(i)) { index = i; i = 0; isStartWeek = false; // 补完你的逻辑 } } // 生成并填充日程详情实例 var scheduleItem = new ScheduleDetailsView { // 赋值属性,比如Week = week.ElementAt(i) }; scheduleDetailsViews.Add(scheduleItem); } return scheduleDetailsViews; }
这种方式下:
- 如果你需要后续更新这个"可枚举集合",只要保留对
scheduleDetailsViews的引用,直接修改List里的元素、添加新元素,下次遍历这个返回的IEnumerable时,就能拿到最新的内容。 - 如果不想让外部直接修改这个List,可以返回它的只读包装:
return scheduleDetailsViews.AsReadOnly();,这样外部只能遍历,不能修改集合本身。
2. 利用延迟执行实现"动态更新"
如果你希望每次遍历这个IEnumerable时,都能生成最新的日程结构(而不是返回固定的旧数据),可以去掉中间的List,改用yield return自定义迭代器:
public IEnumerable<ScheduleDetailsView> StructureSchedule() { bool isStartWeek = false; int index = -1; var week = Enum.GetValues(typeof(Week)).Cast<Week>(); var weekLength = Enum.GetNames(typeof(Week)).Length; for (int i = 0; i < weekLength; i++) { if (isStartWeek) { if (WorkingGroup.WeekStart == week.ElementAt(i)) { index = i; i = 0; isStartWeek = false; // 补完逻辑 } } // 每次遍历都会重新生成这个实例,拿到最新的WorkingGroup状态 var scheduleItem = new ScheduleDetailsView { Week = week.ElementAt(i), // 其他属性可以基于当前最新的业务数据赋值 }; yield return scheduleItem; } }
这种方式的特点是:
- 每次调用
StructureSchedule()并开始遍历的时候,都会重新执行整个迭代逻辑,相当于实时生成最新的元素。 - 如果想固定某次生成的结果,避免每次遍历都重新计算,只要把结果转成List/Array:
var fixedSchedule = StructureSchedule().ToList();,后续遍历fixedSchedule就会用缓存的旧数据。
3. 区分延迟执行与立即执行的坑
很多新手会踩的一个坑:如果你的IEnumerable是通过LINQ查询生成的(比如week.Where(w => ...)),它是延迟执行的——每次遍历都会重新执行查询。如果你的数据源(比如WorkingGroup的状态)发生了变化,每次遍历拿到的结果都会不一样。
如果你想固定查询结果,一定要用ToList()/ToArray()把它转换成立即执行的集合,这样结果就会被缓存下来,后续不会随数据源变化而更新。
额外注意:线程安全问题
如果你的IEnumerable背后的集合会被多个线程同时修改和遍历,一定要注意线程安全。比如改用ConcurrentBag<T>这种线程安全的集合,或者在修改/遍历的时候加锁,避免抛出InvalidOperationException。
内容的提问来源于stack exchange,提问作者Anyname Donotcare

