C# MongoDB Driver反序列化时忽略非字符串类型的Code与Name字段
解决MongoDB Driver反序列化时忽略特定格式字段的问题
核心问题说明
你用SetIgnoreExtraElements无效的原因很明确:这个方法只负责忽略模型中未定义的额外字段,但Case1里的Code、Name是模型已经定义好的字段,只是存储类型和模型定义的string不匹配,驱动会尝试反序列化而非直接忽略。你的需求是:遇到Code、Name是带"_t":"JsonElement"的对象时跳过这两个字段,保留Destinations;遇到它们是字符串时正常反序列化。
解决方案:自定义字段序列化转换器
针对这种混合结构的字段,需要给Code和Name字段写一个自定义的序列化转换器,在反序列化时判断字段类型,灵活处理两种情况。
1. 编写自定义转换器
public class StringOrJsonElementSkipSerializer : IBsonSerializer<string> { public Type ValueType => typeof(string); // 序列化逻辑:直接按字符串写入即可 public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, string value) { context.Writer.WriteString(value); } // 反序列化逻辑:判断字段类型,按需处理 public string Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var currentType = context.Reader.GetCurrentBsonType(); // 如果是字符串,正常读取 if (currentType == BsonType.String) { return context.Reader.ReadString(); } // 如果是文档(对应Case1的JsonElement对象),跳过整个字段,返回null或空字符串 else if (currentType == BsonType.Document) { context.Reader.SkipValue(); return null; // 也可以返回string.Empty,根据你的业务需求调整 } // 其他未知类型同样跳过 else { context.Reader.SkipValue(); return null; } } // 实现非泛型接口的方法(必须) object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { return Deserialize(context, args); } void IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { Serialize(context, args, (string)value); } }
2. 在模型中应用转换器
假设你的Booking和Country模型是这样的,直接给Code、Name字段加上特性标记即可:
public class Booking { public ObjectId Id { get; set; } public Country Countries { get; set; } // 其他业务字段... } public class Country { // 给Code字段绑定自定义转换器 [BsonSerializer(typeof(StringOrJsonElementSkipSerializer))] public string Code { get; set; } // 给Name字段绑定自定义转换器 [BsonSerializer(typeof(StringOrJsonElementSkipSerializer))] public string Name { get; set; } // Destinations字段正常保留,不需要特殊处理 public List<string> Destinations { get; set; } }
3. 可选:全局注册转换器
如果不想在每个字段上加特性,也可以全局注册这个转换器,作用于所有string类型的指定字段:
var registry = BsonSerializer.SerializerRegistry; var countrySerializer = registry.GetSerializer<Country>(); var modifiedRegistry = new AttributeSerializerRegistry(registry, new[] { new StringOrJsonElementSkipSerializer() }); BsonSerializer.RegisterSerializer(modifiedRegistry);
效果验证
- 处理Case1文档时:Code和Name会被跳过(返回null),Destinations字段正常读取
- 处理Case2文档时:Code和Name会正常读取字符串值
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

