You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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再合并结果的场景,不是逻辑没问题。

修复方案

  1. 修改productsRepo.GetProducts的实现,保证每一条查询结果都创建新的Product实例,不要复用类级别/全局的实体对象
  2. 如果用了映射工具,修改配置强制每次映射生成新的实体实例
  3. 补充对应的单元测试:连续两次调用GetProducts获取不同门店的产品,校验两次返回的集合元素属性不会互相影响

内容的提问来源于stack exchange,提问作者lrv-eps

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 07:06:04