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
相关产品推荐
相关产品推荐

