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

.NET Core 3.1 MongoDB反序列化Dictionary转List类型异常排查

根因分析

异常触发点在ClauseKeysValueDocument类的ValueListDict属性实现,核心问题是序列化和反序列化逻辑不匹配:

  • 属性getter直接返回Dictionary<string, ClauseEnumDocument>类型的私有字段,MongoDB C#驱动序列化写入数据时,会直接把该值按BSON文档(字典结构)存储到MongoDB中
  • 属性setter硬编码将传入值强转为List<object>类型,反序列化读取数据时,驱动从库中读出之前写入的字典类型值,直接强转List就会抛出你看到的类型转换异常
  • 原代码本意是绕开.NET Core 3.1对非string键字典序列化的限制,但只实现了数组转字典的反序列化逻辑,没有对应实现字典转数组的序列化逻辑,导致读写数据格式完全不一致
  • 异常栈里提示的ClauseDocument.KeysValue属性本身没有逻辑错误,只是因为它存储的列表元素包含ClauseKeysValueDocument实例,异常逐层向上抛出时被标记为出错属性
修复方案

调整ValueListDict属性的实现,保证序列化输出格式和反序列化预期格式一致,同时兼容历史已存储的旧数据,修正后的核心代码如下:

public class ClauseKeysValueDocument
{
    [BsonIgnoreIfNull]
    public string ListSeparatorValues { get; set; }
    [BsonIgnoreIfNull]
    private Dictionary<string, ClauseEnumDocument> _ValueListDict { get; set; }

    [BsonIgnoreIfNull]
    public object ValueListDict
    {
        get 
        { 
            // 序列化时将字典转为setter预期的数组结构,保证读写格式统一
            var arrayFormat = new List<object>();
            foreach (var keyValuePair in _ValueListDict)
            {
                arrayFormat.Add(new List<object> { keyValuePair.Key, keyValuePair.Value });
            }
            return arrayFormat;
        }
        set 
        {
            // 兼容历史已经被序列化为字典格式的存量数据,无需洗数
            if (value is Dictionary<string, ClauseEnumDocument> storedDict)
            {
                _ValueListDict = storedDict;
                return;
            }
            // 处理正常数组格式的存储值
            var dictAsArray = (List<object>)value;
            var dict = new Dictionary<string, ClauseEnumDocument>();
            foreach (var item in dictAsArray)
            {
                var keyValueItem = (List<object>)item;
                dict.Add(keyValueItem[0].ToString(), (ClauseEnumDocument)keyValueItem[1]);
            }
            _ValueListDict = dict;
        }
    }
    // 其余属性保持原有定义不变
    [BsonIgnoreIfNull]
    public String StateCode { get; set; }
    [BsonIgnoreIfNull]
    public String RecordStateCode { get; set; }
    [BsonIgnoreIfNull]
    public DateTime StartDate { get; set; }
    [BsonIgnoreIfNull]
    public DateTime? EndDate { get; set; }
    [BsonIgnoreIfNull]
    public int ProgNumberToCancel { get; set; }
    [BsonIgnoreIfNull]
    public Int32 ProgNumber { get; set; }
    [BsonIgnoreIfNull]
    public String Value { get; set; }
}

修复说明:

  • 调整getter逻辑,序列化时主动将字典转为List<object>结构,后续新写入的数据都会按数组格式存储,从根源消除类型不匹配问题
  • setter增加类型判断分支,直接识别历史存量数据中已经存为字典格式的值,不需要批量修改库中已有数据即可完成兼容
  • 如果后续框架升级到.NET 5及以上版本,可以删除这个自定义转换的object属性,直接将私有字典字段改为公开属性,使用MongoDB驱动原生的字典序列化能力即可,减少自定义维护成本

内容的提问来源于stack exchange,提问作者RP_PC_Net

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:09:16