如何避免Razor视图中两个独立Batch列表被意外修改?
问题
我通过页面模型在Razor视图中创建了两个独立的Batch列表:
@model IEnumerable<Batch> @{ ViewBag.Title = "Batches"; bool FirstEveningBatch = true; List<Batch> WeekDaysBatch = new List<Batch>(Model.ToList()); List<Batch> WeekEndBatch = new List<Batch>(Model.ToList()); }
随后调用第一个列表的扩展方法:
@foreach (var item in WeekDaysBatch.Where(x => !x.IsWeekendBatch).AppendBatchNumber()) { // ... some code ... }
AppendBatchNumber扩展方法代码:
public static IEnumerable<Batch> AppendBatchNumber(this IEnumerable<Batch> batches) { bool IsFirstEveningBatch = true; int batchnumber = 0; Batch[] batchesArray = batches.OrderBy(x=> x.StartTime).ToArray(); for (int i = 0; i < batchesArray.Length; i++) { if (batchesArray[i].Name.StartsWith("Evening") && IsFirstEveningBatch) { batchnumber = 0; IsFirstEveningBatch = false; } batchesArray[i].Name = string.Format("{0}-{1}", batchesArray[i].Name, ++batchnumber); } return batchesArray; }
但第二个列表WeekEndBatch也被修改了,请问如何避免这种情况?
Batch类定义:
public class Batch { public int Id { get; set; } public string Name { get; set; } [NoBatchAfter9PM] public TimeSpan StartTime { get; set; } [NoBatchAfter9PM] public TimeSpan EndTime { get; set; } public string? Description { get; set; } [Display(Name="Is it a Weekend batch?")] public bool IsWeekendBatch { get; set; } [Display(Name = "Is it a Women's batch?")] public bool IsWomenBatch { get; set; } public ICollection<Learner>? Learners { get; set; } public Coach? Coach { get; set; } }
解决方案
问题根源
你创建的两个列表虽然是独立的集合容器,但它们存储的是同一个Batch对象的引用。当扩展方法修改batchesArray[i].Name时,实际是直接修改了原对象的属性值,所有持有该对象引用的列表都会同步看到变化。
具体解决办法
1. 创建Batch对象的独立副本
在初始化两个列表时,不要直接复制对象引用,而是为每个Batch创建新实例:
List<Batch> WeekDaysBatch = Model.Select(b => new Batch { Id = b.Id, Name = b.Name, StartTime = b.StartTime, EndTime = b.EndTime, Description = b.Description, IsWeekendBatch = b.IsWeekendBatch, IsWomenBatch = b.IsWomenBatch, // 如果Learners和Coach不需要完全独立,可直接引用;否则需递归拷贝 Learners = b.Learners?.ToList(), Coach = b.Coach }).ToList(); List<Batch> WeekEndBatch = Model.Select(b => new Batch { Id = b.Id, Name = b.Name, StartTime = b.StartTime, EndTime = b.EndTime, Description = b.Description, IsWeekendBatch = b.IsWeekendBatch, IsWomenBatch = b.IsWomenBatch, Learners = b.Learners?.ToList(), Coach = b.Coach }).ToList();
2. 修改扩展方法,不修改原对象
调整AppendBatchNumber方法,返回新的Batch实例而非修改原对象:
public static IEnumerable<Batch> AppendBatchNumber(this IEnumerable<Batch> batches) { bool IsFirstEveningBatch = true; int batchnumber = 0; var orderedBatches = batches.OrderBy(x => x.StartTime); foreach (var batch in orderedBatches) { if (batch.Name.StartsWith("Evening") && IsFirstEveningBatch) { batchnumber = 0; IsFirstEveningBatch = false; } // 返回新实例,原对象不受影响 yield return new Batch { Id = batch.Id, Name = string.Format("{0}-{1}", batch.Name, ++batchnumber), StartTime = batch.StartTime, EndTime = batch.EndTime, Description = batch.Description, IsWeekendBatch = batch.IsWeekendBatch, IsWomenBatch = batch.IsWomenBatch, Learners = batch.Learners, Coach = batch.Coach }; } }
3. 为Batch类添加克隆方法
在Batch类中实现克隆逻辑,方便复用:
public class Batch { // 原有属性... public Batch Clone() { return new Batch { Id = this.Id, Name = this.Name, StartTime = this.StartTime, EndTime = this.EndTime, Description = this.Description, IsWeekendBatch = this.IsWeekendBatch, IsWomenBatch = this.IsWomenBatch, Learners = this.Learners?.ToList(), Coach = this.Coach // 若Coach是引用类型,需同步实现Clone方法 }; } }
之后创建列表时直接调用克隆方法:
List<Batch> WeekDaysBatch = Model.Select(b => b.Clone()).ToList(); List<Batch> WeekEndBatch = Model.Select(b => b.Clone()).ToList();
内容的提问来源于stack exchange,提问作者Sagar Tube
相关产品推荐
相关产品推荐

