从 .NET 对象到 JSON 到 BSON,同时避免 _t/_v 编码,将导致日期和其他 BSON 特定类型的类型信息丢失。
我发现在保留 BSON 类型的同时避免 _t/_v 的解决方案是为驱动程序的内置DictionaryInterfaceImplementerSerializer
(以及可选的EnumerableInterfaceImplementerSerializer
)注册一个自定义值序列化程序。我已经测试了“扩展 JSON”生成的解决方案,即针对 BSON 特定类型具有特殊语法的 JSON,但对于直接 BSON 输出,原理应该相同。
为此,首先将标准复制ObjectSerializer
到您的 C# 项目中(并重命名以避免歧义):https ://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/Serialization/Serializers /ObjectSerializer.cs
除了类重命名,private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)
方法也需要编辑。(就我而言,我还想避免 _t/_v 编码IEnumerable<object>
,如下所示。)
private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)
{
var serializer = BsonSerializer.LookupSerializer(actualType);
var polymorphicSerializer = serializer as IBsonPolymorphicSerializer;
// Added line
var assignableToDictionaryOrEnumerable = typeof(IDictionary<string, object>).IsAssignableFrom(actualType) || typeof(IEnumerable<object>).IsAssignableFrom(actualType);
if (polymorphicSerializer != null && polymorphicSerializer.IsDiscriminatorCompatibleWithObjectSerializer)
{
serializer.Serialize(context, args, value);
}
else
{
// Edited line
if (assignableToDictionaryOrEnumerable || (context.IsDynamicType != null && context.IsDynamicType(value.GetType())))
{
// We want this code to be executed for types that should be serialized without _t and _v fields
args.NominalType = actualType;
serializer.Serialize(context, args, value);
}
else
{
var bsonWriter = context.Writer;
var discriminator = _discriminatorConvention.GetDiscriminator(typeof(object), actualType);
bsonWriter.WriteStartDocument();
bsonWriter.WriteName(_discriminatorConvention.ElementName);
BsonValueSerializer.Instance.Serialize(context, discriminator);
bsonWriter.WriteName("_v");
serializer.Serialize(context, value);
bsonWriter.WriteEndDocument();
}
}
}
假设复制和编辑的类的名称是DynamicValueSerializer
,使用以下代码在应用程序启动时将其注册为值序列化器。
BsonSerializer.RegisterSerializer(typeof(Dictionary<string, object>),
new DictionaryInterfaceImplementerSerializer<Dictionary<string, object>, string, object>(
DictionaryRepresentation.Document,
new StringSerializer(),
new DynamicValueSerializer()));
请注意,必须为每个实际类型执行此操作,它应该用于其值。无法对接口进行序列化程序注册。因此,如果SortedDictionary<string, object>
或SortedList<string, object>
要以与 相同的方式处理Dictionary<string, object>
,则需要为这些类型重复注册。(这会影响作为值包含在这些类型集合中的字典是否会在没有 _t/_v 的情况下进行序列化,不一定会影响这些类型的对象本身是否会以这种方式序列化。)
要将相同的序列化原则应用于List<object>
对象,请使用以下注册码。
BsonSerializer.RegisterSerializer(typeof(List<object>),
new EnumerableInterfaceImplementerSerializer<List<object>, object>(
new DynamicValueSerializer()));