C# 字典<;字符串,对象>-到b忽略字段的声文档转换

C# 字典<;字符串,对象>-到b忽略字段的声文档转换,c#,mongodb,dictionary,bson,C#,Mongodb,Dictionary,Bson,我正在使用MongoDB.Bson中的ToBsonDocument扩展方法来转换此词典: var dictionary = new Dictionary<string, object> {{"person", new Dictionary<string, object> {{"name", "John"}}}}; var document = dictionary.ToBsonDocument(); 有没有办法摆脱这些东西?我希望生成的文

我正在使用
MongoDB.Bson
中的
ToBsonDocument
扩展方法来转换此词典:

        var dictionary = new Dictionary<string, object> {{"person", new Dictionary<string, object> {{"name", "John"}}}};
        var document = dictionary.ToBsonDocument();
有没有办法摆脱这些东西?我希望生成的文档如下所示:

  { "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

时,此序列化程序似乎没有太多选项,这是因为您为字典值指定了
object
类型,但实际为特定记录值使用了
dictionary
类型。因此,CSharp驱动程序保存了具体类型的全名,以便将来正确地反序列化此文档。您还可以在此处阅读更多信息:

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

var dictionary = new Dictionary<string, Dictionary<string, object>>
{
    { "person", new Dictionary<string, object> { { "name", "John" } } }
};
var document = dictionary.ToBsonDocument();
var字典=新字典
{
{“人”,新字典{{“名字”,“约翰”}
};
var document=dictionary.ToBsonDocument();

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

var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary);
var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(jsonDoc);
var jsonDoc=Newtonsoft.Json.JsonConvert.SerializeObject(字典);
var bsonDoc=MongoDB.Bson.Serialization.BsonSerializer.Deserialize(jsonDoc);

从对象到BSON的直接转换很困难

而是从object-->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<BsonDocument>(json);
//对象-->JSON
使用System.Web.Extensions;
使用System.Web;
使用System.Web.Script.Serialization;
JavaScriptSerializer js=新的JavaScriptSerializer();
字符串json=js.Serialize(poco);//poco是您的类对象
//JSON-->BSON
MongoDB.Bson.BsonDocument document=MongoDB.Bson.Serialization.BsonSerializer.Deserialize(json);

从.NET对象到JSON再到BSON,同时避免_t/_v编码,将导致日期和其他BSON特定类型的类型信息丢失

我找到的在保留BSON类型的同时避免_t/_v的解决方案是为驱动程序的内置
字典InterfaceImplementerSerializer
(以及可选的
枚举接口实现器serializer
)注册一个自定义值序列化器。我已经测试了“扩展JSON”生成的解决方案,即针对BSON特定类型使用特殊语法的JSON,但对于直接BSON输出,原理应该是相同的

为此,首先将标准的
ObjectSerializer
复制到您的C#project中(并将其重命名以避免歧义):

除了类重命名之外,
private void serializedValue(BsonSerializationContext,BsonSerializationArgs args,object value,Type actualType)
方法也需要编辑。(在我的例子中,我还希望避免对
IEnumerable
进行_t/_v编码,如下所示。)

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

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

BsonSerializer.RegisterSerializer(typeof(List<object>),
    new EnumerableInterfaceImplementerSerializer<List<object>, object>(
        new DynamicValueSerializer()));
BsonSerializer.RegisterSerializer(类型(列表),
新的EnumerableInterfaceImplementerSerializer(
新的DynamicValueSerializer());

是的,如果我为值指定具体类型,它可以正常工作。但在我的例子中,任何值都可以是
字符串
值或另一个
字典
。因此,对于类型,我似乎只能使用
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();
            }
        }
    }
BsonSerializer.RegisterSerializer(typeof(Dictionary<string, object>),
    new DictionaryInterfaceImplementerSerializer<Dictionary<string, object>, string, object>(
        DictionaryRepresentation.Document,
        new StringSerializer(),
        new DynamicValueSerializer()));
BsonSerializer.RegisterSerializer(typeof(List<object>),
    new EnumerableInterfaceImplementerSerializer<List<object>, object>(
        new DynamicValueSerializer()));