Docs 菜单
Docs 主页
/ / /
C#/.NET
/ /

多态对象

在此页面上

  • Overview
  • 反序列化多态对象
  • 使用鉴别器
  • ScalarDiscriminatorConvention
  • HierarchicalDiscriminatorConvention
  • 自定义鉴别器惯例

多态对象从一个或多个父类继承属性和方法。这些对象需要特殊的映射,以确保 .NET/C# 驱动程序能正确地将其序列化到 BSON 文档或从 BSON 文档序列化出来。

本指南解释了以下内容:

  • 如何反序列化多态类型

  • .NET/C# 驱动程序附带的鉴别器惯例

  • 如何创建自定义鉴别器约定

本页中的示例使用以下继承层次结构:

public class Animal
{
}
public class Cat : Animal
{
}
public class Dog : Animal
{
}
public class Lion : Cat
{
}
public class Tiger : Cat
{
}

在序列化程序可以反序列化任何多态对象之前,您必须记录继承层次结构中所有类的关系。

如果您使用自动映射器来映射类,请将 [BsonKnownTypes]属性应用于层次结构中的每个基类。 将从基类直接继承的每个类作为参数传递。

下方的示例演示如何将 [BsonKnownTypes] 属性应用于示例 Animal 层次结构的类中:

[BsonKnownTypes(typeof(Cat), typeof(Dog))]
public class Animal
{
}
[BsonKnownTypes(typeof(Lion), typeof(Tiger))]
public class Cat : Animal
{
}
public class Dog : Animal
{
}
public class Lion : Cat
{
}
public class Tiger : Cat
{
}

注意

Using BsonKnownTypes

仅将 [BsonKnownTypes] 属性应用于父类。只传递直接继承自类的类型作为参数,而非层次结构中的所有子类。

如果手动创建类映射,请为层次结构中的每个类调用 BsonClassMap.RegisterClassMap<T>() 方法,如下例所示:

BsonClassMap.RegisterClassMap<Animal>();
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
BsonClassMap.RegisterClassMap<Lion>();
BsonClassMap.RegisterClassMap<Tiger>();

提示

类映射

要学习;了解有关映射类的详情,请参阅类映射文档。

在 MongoDB 中,鉴别器是添加到文档中的字段,用于标识文档反序列化到的类。 当collection包含来自单个继承层次结构的多个类型时,鉴别器可确保每个文档反序列化为正确的类。.NET/C# 驱动程序将鉴别器值存储在 BSON 文档中名为_t的字段中。 通常, _t是 BSON 文档中继_id之后的第二个字段。

鉴别器约定定义存储在鉴别器字段中的值。在本部分中,您可以了解 .NET/C# 驱动程序中包含的鉴别器约定以及如何创建自定义鉴别器约定。

默认情况下,.NET/C# 驱动程序使用 ScalarDiscriminatorConvention。根据此规则,.NET/C# 驱动程序将 _t 字段的值设置为文档从中序列化的类的名称。

假设您创建示例 Animal 类及其每个子类的实例。如果将这些对象序列化到单个集合,则 .NET/C# 驱动程序将应用 ScalarDiscriminatorConvention ,相应的 BSON 文档将如下所示:

{ _id: ..., _t: "Animal", ... }
{ _id: ..., _t: "Cat", ... }
{ _id: ..., _t: "Dog", ... }
{ _id: ..., _t: "Lion", ... }
{ _id: ..., _t: "Tiger", ... }

ScalarDiscriminatorConvention 使用简洁的鉴别器值,但很难运行查询。例如,要查找类型或子类型为 Cat 的所有文档,您必须明确列出要查找的每个类:

var query = coll.AsQueryable().Where(
item => item.GetType() == typeof(Cat) ||
item.GetType() == typeof(Lion) ||
item.GetType() == typeof(Tiger));

注意

OfType<T>() 和 is 操作符

检查标量鉴别器的类型时,请使用前面的代码示例所示的 Where 语法。如果您尝试使用 Aggregate().OfType<T>() 方法,或者将包含 is操作符的表达式传递给 Aggregate().Match() 方法,驾驶员会引发异常。

要简化对多态类型集合的查询,您可以使用 HierarchicalDiscriminatorConvention。根据这一惯例,_t 的值是文档类型的继承层次结构中所有类的数组。

要使用 HierarchicalDiscriminatorConvention,请将继承层次结构的基类标记为根类。如果使用的是自动映射器,请通过将 [BsonDiscriminatorAttribute] 属性应用于类并将 RootClass = true 作为参数传递来标记根类。下面的代码示例将 Animal 类标记为示例继承层次结构的根:

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Cat), typeof(Dog)]
public class Animal
{
}

如果手动创建类映射,请调用 SetIsRootClass() 方法,在注册根类的类映射时传递 true 作为参数。以下代码示例注册所有五个示例类的类映射,但仅将 Animal 类标记为继承层次结构的根:

BsonClassMap.RegisterClassMap<Animal>(classMap => {
classMap.AutoMap();
classMap.SetIsRootClass(true);
});
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
BsonClassMap.RegisterClassMap<Lion>();
BsonClassMap.RegisterClassMap<Tiger>();

假设您将示例 Animal 类标记为继承层次结构的根,然后创建 Animal 类及其每个子类的实例。如果您将这些对象序列化为单个集合,.NET/C# 驱动程序会应用 HierarchicalDiscriminatorConvention,相应的 BSON 文档如下所示:

{ _id: ..., _t: "Animal", ... }
{ _id: ..., _t: ["Animal", "Cat"], ... }
{ _id: ..., _t: ["Animal", "Dog"], ... }
{ _id: ..., _t: ["Animal", "Cat", "Lion"], ... }
{ _id: ..., _t: ["Animal", "Cat", "Tiger"], ... }

重要

根类别鉴别器

映射到根类的任何文档仍使用字符串值作为鉴别器字段。

使用 HierarchicalDiscriminatorConvention 时,您可以使用单个布尔值条件搜索 Cat 类型或子类型的所有文档,如下例所示:

var query = coll.Aggregate().Match(a => a is Cat);

如果所处理数据不遵循 .NET/C# 驱动程序使用的约定,例如,由其他驱动程序或对象映射器插入 MongoDB 的数据,那么您可能需要为鉴别器字段使用不同的值,以确保类符合这些约定。

如果使用的是自动映射器,请通过将 [BsonDiscriminator] 属性应用于类并将自定义判别器值作为字符串参数传递,从而为类的鉴别器字段指定自定义值。以下代码示例将 Animal 类的鉴别器字段值设置为“myAnimalClass”:

[BsonDiscriminator("myAnimalClass")]
public class Animal
{
}

如果手动创建类映射,请调用 SetDiscriminator() 方法,在注册类映射时将自定义鉴别器值作为参数传递。以下代码示例将 Animal 类的鉴别器字段值设置为“myAnimalClass”:

BsonClassMap.RegisterClassMap<Animal>(classMap =>
{
classMap.AutoMap();
classMap.SetDiscriminator("myAnimalClass");
});

序列化后,先前 Animal 类的实例如下所示:

{ "_id": "...", "_t": "myAnimalClass"}

后退

POCO