MongoDB反序列化报错:无法创建抽象类Test实例
问题描述
我定义了以下C#类:
public abstract class Test { } public class ConcreteTest1: Test { public string Foo {get; set; } //... } public class ConcreteTest2: Test { public int AnInt { get; set; } //... } public class TestScript { public ObjectId _id { get; set; } = new(); public string PartNumber { get; set; } public IList<Test> Tests { get; set; } = []; }
将TestScript存储到MongoDB时一切正常,但检索时抛出错误:
System.FormatException: 'An error occurred while deserializing the Tests property of class TestScript: Cannot create an instance of Test because it is an abstract class.'
MongoDB中的文档结构如下:
{ "_id": { "$oid": "6780467598922ae42e13a832" }, "PartNumber": "1234-12345-12", "Tests": [ { "_t": "ConcreteTest1", "Foo": "bar", ... }, { "_t": "ConcreteTest2", "AnInt": 42 ... } ] }
检索代码:
var collection = db.GetCollection<TestScript>("TestScripts"); var testScript = await collection.Find(ts => ts.PartNumber == partNumber).SingleOrDefaultAsync(cancellationToken); return testScript?.Tests ?? [];
如何让反序列化器识别子类类型?文档中已经包含_t类型标识,应该可以利用它。另外我是首次使用MongoDB,若有其他不当之处也请指出。
解决方案
MongoDB .NET驱动需要明确知道抽象基类的所有实现类型,才能正确解析_t类型标识完成反序列化,有两种常用配置方式:
方式一:使用特性标记已知类型
直接在抽象基类Test上添加[BsonKnownTypes]特性,列出所有子类:
[BsonKnownTypes(typeof(ConcreteTest1), typeof(ConcreteTest2))] public abstract class Test { }
驱动在反序列化时会自动根据文档中的_t值匹配对应的子类。
方式二:代码配置类映射
如果不想在实体类中添加MongoDB专属特性,可以在程序初始化阶段(比如Program.cs启动时)配置类映射:
BsonClassMap.RegisterClassMap<Test>(cm => { cm.AutoMap(); cm.AddKnownType(typeof(ConcreteTest1)); cm.AddKnownType(typeof(ConcreteTest2)); });
这种方式更灵活,适合需要保持实体类纯净的场景。
额外注意点
- 确保文档中的
_t值和子类的类名完全一致(区分大小写),如果子类带有命名空间,可能需要在_t中包含命名空间,或者通过配置自定义类型名称规则。 - 存储时驱动自动生成
_t字段是默认启用了多态序列化,检索时必须配置已知类型才能正确解析。 - 后续新增
Test的子类时,需要同步更新已知类型配置(无论是特性还是代码映射),否则反序列化新子类实例会报错。
内容的提问来源于stack exchange,提问作者RoadieRich
相关产品推荐
相关产品推荐

