.NET 4.6.1下MongoDB抽象子类反序列化忽略字段失效问题
哈哈,这个坑我之前踩过!你遇到的问题其实是MongoDB C#驱动2.5.0版本在处理抽象类+子类反序列化时,BsonIgnoreExtraElements特性的生效范围很容易让人误解,哪怕你以为所有类都加了特性,还是会踩雷。
核心原因
驱动在反序列化带有抽象类型字段的文档时,会先根据鉴别器(默认是_t字段)找到对应的子类类型,然后单独对该子类进行反序列化。这时候如果子类的忽略多余元素配置没有正确生效,哪怕父类/抽象类加了特性,也没用。
你可能遗漏的几个关键点:
子类必须显式添加
BsonIgnoreExtraElements:
别以为抽象类加了特性子类就自动继承了!在2.5.0这个老版本里,抽象类的BsonIgnoreExtraElements不会传递给子类,必须在Child1上单独声明:[BsonIgnoreExtraElements(true)] [BsonKnownTypes(typeof(Child1))] public abstract class MyAbstract { /* ... */ } [BsonIgnoreExtraElements(true)] // 这行不能少! public class Child1 : MyAbstract { /* ... */ }哪怕你之前觉得加了,再仔细检查一遍,说不定是复制粘贴的时候漏了。
手动ClassMap配置会覆盖特性:
如果你的项目里手动注册了Child1的BsonClassMap(比如启动时写了BsonClassMap.RegisterClassMap<Child1>()),那类上的特性可能会被手动配置覆盖。一定要确保在注册时开启忽略:BsonClassMap.RegisterClassMap<Child1>(cm => { cm.AutoMap(); // 先自动映射,保留类上的特性配置 cm.IgnoreExtraElements = true; // 显式设置,双重保险 });要是你没调用
AutoMap()而是手动一个个加字段,驱动会完全忽略类上的特性,必须手动开忽略。鉴别器字段是否正确:
去MongoDB里看看Child1文档的_t字段是不是准确指向Child1类型。如果鉴别器错了,驱动可能会尝试用抽象类MyAbstract去反序列化——抽象类不能实例化,哪怕有忽略特性也会报错。临时应急方案:
要是暂时没时间改代码或升级驱动,也可以在反序列化时强制指定忽略选项:var deserializeOptions = new BsonDeserializationOptions { IgnoreExtraElements = true }; // 查询时指定选项 var fatherDoc = collection.Find(filter).FirstOrDefault(); // 或者单独反序列化文档时用 var child = BsonSerializer.Deserialize<Child1>(bsonDoc, deserializeOptions);
额外建议
MongoDB C#驱动在2.7版本之后修复了不少这类抽象类特性继承的bug,要是项目允许,建议升级到较新的稳定版,能少踩很多老版本的坑。
内容的提问来源于stack exchange,提问作者Ori Refael

