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

C# MongoDB:如何更新Dictionary<枚举, int>字段并解决序列化错误?

问题描述

代码结构

public class User
{
    public Dictionary<UserProperty, int> Properties;
}

public enum UserProperty
{
    // 大量属性
}

public class DatabaseManager
{
    BsonSerializer.RegisterSerializer(new EnumSerializer<UserProperty>(BsonType.String));
    static IMongoCollection<User> Users;

    public async Task UpdateUserProperty(User user, UserProperty prop, int value)
    {
        var filter = Builders<User>.Filter.Where(u => u.Id == user.id);
        var update = Builders<User>.Update.Set(u => u.Properties[prop], value);
        await Users.UpdateOneAsync(filter, update); // 抛出异常
    }
}

报错信息

Unable to determine the serialization information for u => u.Properties.get_Item(value(DatabaseManager+<>c__DisplayClass29_0).prop)

用户尝试过用字符串路径 "Properties." + prop.ToString() 替代lambda表达式,但这种写法没有编译时类型检查,也缺乏错误处理机制。

解决方案

方法一:用表达式树构建类型安全的更新路径

手动构建表达式树,让MongoDB驱动能正确解析字典的索引操作,同时保留编译时类型检查:

public async Task UpdateUserProperty(User user, UserProperty prop, int value)
{
    var filter = Builders<User>.Filter.Where(u => u.Id == user.id);
    
    // 构建访问Properties[prop]的表达式
    var userParam = Expression.Parameter(typeof(User), "u");
    var propertiesProp = Expression.Property(userParam, nameof(User.Properties));
    var enumConstant = Expression.Constant(prop);
    var indexAccess = Expression.Index(propertiesProp, enumConstant);
    
    var update = Builders<User>.Update.Set(Expression.Lambda<Func<User, int>>(indexAccess, userParam), value);
    
    await Users.UpdateOneAsync(filter, update);
}

方法二:字符串路径加编译时验证

如果倾向于用字符串路径,可以通过静态映射类维护枚举与路径的关系,同时添加验证逻辑:

// 静态类维护枚举到路径的映射,统一管理避免硬编码
public static class UserPropertyPath
{
    public static string Get(UserProperty prop)
    {
        // 可添加枚举有效性校验,比如检查是否是定义的枚举值
        if (!Enum.IsDefined(typeof(UserProperty), prop))
        {
            throw new ArgumentOutOfRangeException(nameof(prop), "无效的用户属性枚举值");
        }
        return $"Properties.{prop.ToString()}";
    }
}

// 更新方法
public async Task UpdateUserProperty(User user, UserProperty prop, int value)
{
    var filter = Builders<User>.Filter.Where(u => u.Id == user.id);
    var path = UserPropertyPath.Get(prop);
    var update = Builders<User>.Update.Set(path, value);
    await Users.UpdateOneAsync(filter, update);
}

方法三:配置字典的序列化特性

给User类的Properties字段添加序列化特性,明确指定字典键的序列化方式,帮助驱动正确识别索引操作:

public class User
{
    [BsonDictionaryOptions(DictionaryRepresentation.Document, KeySerializerType = typeof(EnumSerializer<UserProperty>))]
    public Dictionary<UserProperty, int> Properties;
}

配置完成后,原有的lambda表达式写法大概率能正常工作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:25:22