ImmutableList意外被修改求助:如何确保其数据不可篡改?
解决ImmutableList中元素对象属性被意外修改的问题
问题描述
我在Class2中实现了GetItemCode方法,该方法接收条码字符串并返回StkBarcode对象,依赖名为listStkBarcodes的ImmutableList作为参考数据进行匹配。但发现Class1中修改从GetItemCode获取的StkBarcode对象的ItemCode属性后,listStkBarcodes内的对应数据也被修改,尽管代码从未直接编辑该ImmutableList。
相关代码片段:
// Class2中的ImmutableList定义 private ImmutableList<StkBarcode> listStkBarcodes; // 调用GetItemCode的代码 StkBarcode objStkBc = await helper.GetItemCode(strBarcode, TheShippers, ShipperMfCodesList); // ImmutableList的填充方法 public async Task<ImmutableList<StkBarcode>> GetReadOnlyStkBarcodes() { ImmutableList<StkBarcode> TheList = ImmutableList.Create<StkBarcode>(); List<StkBarcode> theList = await _context.StkBarcodes.Where(b => b.ItemCode != null && b.Barcode != null).ToListAsync(); TheList = theList.ToImmutableList(); return TheList; } // StkBarcode类定义(略)
问题根源
ImmutableList仅保证集合本身的结构不可变(无法添加、删除、替换元素),但集合中存储的StkBarcode是引用类型,集合保存的是对象的内存引用。当外部获取到这个引用并修改对象属性时,实际修改的是同一块内存中的数据,因此listStkBarcodes内的原对象也会被同步修改。
可行解决方案
1. 将StkBarcode改为不可变类
把StkBarcode的所有属性设置为只读,仅通过构造函数初始化属性,从根源上禁止外部修改对象状态:
public class StkBarcode { public string ItemCode { get; } public string Barcode { get; } // 其他属性同样设置为只读 // 通过构造函数初始化所有属性 public StkBarcode(string itemCode, string barcode /* 其他必要参数 */) { ItemCode = itemCode; Barcode = barcode; // 初始化其他属性 } }
如果需要修改属性值,必须创建新的StkBarcode实例,不会影响原集合中的对象。
2. 返回对象副本而非原引用
在GetItemCode方法中,找到匹配的对象后,创建一个新的StkBarcode实例返回,避免直接返回集合内的对象引用:
public async Task<StkBarcode> GetItemCode(string strBarcode, ...) { var matchedItem = listStkBarcodes.FirstOrDefault(b => b.Barcode == strBarcode); if (matchedItem == null) return null; // 返回新的对象副本 return new StkBarcode { ItemCode = matchedItem.ItemCode, Barcode = matchedItem.Barcode, // 复制其他所有属性 }; }
外部修改返回的副本时,只会影响新实例,不会改动listStkBarcodes中的原对象。
3. 使用C# 9+记录类型(Record)
记录类型默认是不可变的,且支持通过with表达式创建修改后的新实例,适合这种场景:
// 定义记录类型 public record StkBarcode(string ItemCode, string Barcode /* 其他属性 */);
当需要修改属性时,必须通过with创建新实例,原对象保持不变:
// 创建修改后的新实例,原objStkBc不受影响 var modifiedItem = objStkBc with { ItemCode = "new_item_code" };
内容的提问来源于stack exchange,提问作者pdschuller
相关产品推荐
相关产品推荐

