字典 -to-BsonDocument转换省略_t字段

我正在使用ToBsonDocument扩展方法来转换这个字典:

  var dictionary = new Dictionary {{"person", new Dictionary {{"name", "John"}}}}; var document = dictionary.ToBsonDocument(); 

这是结果文件:

  { "person" : { "_t" : "System.Collections.Generic.Dictionary`2[System.String,System.Object]", "_v" : { "name" : "John" } } } 

有没有办法摆脱这些_t / _v的东西? 我希望生成的文档看起来像这样:

  { "person" : { "name" : "John" } } 

UPD:我在DictionaryGenericSerializer中找到了代码:

 if (nominalType == typeof(object)) { var actualType = value.GetType(); bsonWriter.WriteStartDocument(); bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType)); bsonWriter.WriteName("_v"); Serialize(bsonWriter, actualType, value, options); // recursive call replacing nominalType with actualType bsonWriter.WriteEndDocument(); return; } 

因此,当值类型为object时,似乎没有太多选项可用于此序列化程序。

您应首先序列化为JSON,然后序列化为BSON,

 var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary); var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(jsonDoc); 

这是因为您为字典值指定了object类型,但实际上对特定记录值使用了Dictionary类型。 因此,CSharp驱动程序将保存具体类型的全名,以便将来正确反序列化此文档。 您还可以在此处阅读更多相关信息: 使用CSharp驱动程序序列化文档:多态类和鉴别器

要获得所需的结果,您应该为字典值指定具体类型:

 var dictionary = new Dictionary> { { "person", new Dictionary { { "name", "John" } } } }; var document = dictionary.ToBsonDocument(); 

从物体到BSON的直接转换是困难的。

而是从对象– > Json – > Bson

 // Object --> JSON using System.Web.Extensions; using System.Web; using System.Web.Script.Serialization; JavaScriptSerializer js = new JavaScriptSerializer(); string json = js.Serialize(poco); // poco is ur class object //JSON --> BSON MongoDB.Bson.BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(json); 

从.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/串行器/ ObjectSerializer.cs

除了类重命名之外,还需要编辑private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)方法。 (在我的例子中,我也想避免IEnumerable _t / _v编码,这反映在下面。)

  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).IsAssignableFrom(actualType) || typeof(IEnumerable).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), new DictionaryInterfaceImplementerSerializer, string, object>( DictionaryRepresentation.Document, new StringSerializer(), new DynamicValueSerializer())); 

请注意,必须为每个实际类型执行此操作,应使用其值。 无法对接口进行序列化程序注册。 因此,如果SortedDictionarySortedList将以与Dictionary相同的方式处理,则需要对这些类型重复注册。 (这会影响这些类型的集合中包含的字典是否将在没有_t / _v的情况下序列化,不一定是这些类型的对象本身是否会以这种方式序列化。)

要将相同的序列化原则应用于List对象,请使用以下注册码。

 BsonSerializer.RegisterSerializer(typeof(List), new EnumerableInterfaceImplementerSerializer, object>( new DynamicValueSerializer()));