.NET 5 Blazor Server页面加载时List集合数据被第二组覆盖问题
问题根因
你遇到的是典型的引用类型实例复用问题,和Blazor框架、List<T>的AddRange逻辑没有任何关联,问题出在你的productsRepo.GetProducts仓储实现上。
排查验证
你可以先加一行日志确认这个判断:在获取l1和l2之后分别打印集合首元素的哈希码:
var l1 = productsRepo.GetProducts(locations[0], business!.BusinessId); log.LogTrace("l1[0] hash code: {Hash}", l1[0].GetHashCode()); // ... 原有日志 var l2 = productsRepo.GetProducts(locations[1], business!.BusinessId); log.LogTrace("l2[0] hash code: {Hash}", l2[0].GetHashCode());
你会发现两次打印的哈希码完全一致,说明两次查询返回的所有Product本质都是同一个对象的引用。
为什么会出现这个现象
几乎可以肯定是你的GetProducts方法中复用了同一个Product实例,常见的错误实现类似下面这样:
// 错误示例:在类级别定义复用的实体对象 private Product _reusedProduct = new Product(); public List<Product> GetProducts(string location, Guid businessId) { var result = new List<Product>(); foreach (var row in QueryAzureTable(location, businessId)) { // 直接修改复用的实例属性,没有新建对象 _reusedProduct.LocationId = row.LocationId; _reusedProduct.Name = row.Name; // ... 其他属性赋值 result.Add(_reusedProduct); } return result; }
这种实现下,返回的集合里所有元素都是同一个对象的引用,第二次调用GetProducts时修改了这个共享实例的属性,自然第一次已经加到l1里的所有元素属性也会同步更新,合并后自然全是第二次查询的属性值。
另外如果你用了自定义的Azure表存储实体转换器、AutoMapper等工具,也要检查是否配置了「复用目标实例」的逻辑,没有为每行数据创建新的实体对象。
为什么单元测试没覆盖到
通常这种问题会被单元测试遗漏:如果你的单元测试仅验证单次调用GetProducts的返回结果,没有连续两次调用后再校验第一次返回集合的属性,就刚好不会触发这个问题。其他页面没有复现也是因为没有连续两次调用GetProducts再合并结果的场景,不是逻辑没问题。
修复方案
- 修改
productsRepo.GetProducts的实现,保证每一条查询结果都创建新的Product实例,不要复用类级别/全局的实体对象 - 如果用了映射工具,修改配置强制每次映射生成新的实体实例
- 补充对应的单元测试:连续两次调用
GetProducts获取不同门店的产品,校验两次返回的集合元素属性不会互相影响
内容的提问来源于stack exchange,提问作者lrv-eps
相关产品推荐
相关产品推荐

