自定义 BSON 键值序列化器

Custom BSON Key Value Serializer

我 运行 在尝试将 class 转换为 BSON 文档时遇到了一些麻烦。

我有 Custom1Custom2,它们的行为应该有点不同。如何创建一个 "unfold" KeyValuePair 的自定义序列化器,以便它生成预期的结果(见下文)?您可以看到下面的代码示例以及预期结果。

此外,我正在使用 Mongo BSON 库来序列化对象。

public class UserData
{
    public UserData()
    {
        Id = 100;
        Name = "Superuser";
        Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1);
        Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2);
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public KeyValuePair<string, double> Custom1 { get; set; }
    public KeyValuePair<string, double> Custom2 { get; set; }
}

执行测试代码:

var userdata = new UserData();
var doc = userdata.ToBsonDocument();

当前结果:

{
    "Id": 100,
    "Name": "Superuser",
    "Custom1": {
                    "Key": "HelloWorld1",
                    "Value": 1
               },
    "Custom2": {
                    "Key": "HelloWorld2",
                    "Value": 2
               }
}

预期结果:

{
    "Id": 100,
    "Name": "Superuser",
    "HelloWorld1": 1,
    "HelloWorld2": 2
}

如果您使用的是 2.0 或更高版本的驱动程序,您可以尝试将 class 变成 DynamicObject,如下所示:

public class UserData : DynamicObject
{
 public UserData()
  {
    Id = 100;
    Name = "Superuser";
    Custom1 = new KeyValuePair<string, double>("HelloWorld1", 1);
    Custom2 = new KeyValuePair<string, double>("HelloWorld2", 2);
  }

 public id Id { get; set; }
 public string Name { get; set; }
 public KeyValuePair<string, double> Custom1 { get; set; }
 public KeyValuePair<string, double> Custom2 { get; set; }

 public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        string name = binder.Name;
        result = null;
        if(name.Equals(Custom1.Key)) 
            result = Custom1.Value;
        else if(name.Equals(Custom2.Key))
            result = Custom2.Value;
        return result != null;
    }

  public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {         
      string name = binder.Name;
      if(name.Equals(Custom1.Key)) 
        Custom1.Value = value;
      else if(name.Equals(Custom2.Key))
        Custom2.Value = value;
      return name.Equals(Custom1.Key) || 
             name.Equals(Custom2.Key);
    }
  }

根据发布文档,您应该可以这样做:

var userdata = new UserData(); var doc = ((dynamic) userdata).ToBsonDocument();

并获得预期的格式。

对于如此复杂的序列化情况,您必须为您的 class.

实现自定义 IBsonSerializer 转换器

这是工作示例:

public class UserDataSerializer : SerializerBase<UserData>
{
    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, UserData value)
    {
        context.Writer.WriteStartDocument();
        context.Writer.WriteName("Id");
        context.Writer.WriteInt32(value.Id);
        context.Writer.WriteName("Name");
        context.Writer.WriteString(value.Name);

        WriteKeyValue(context.Writer, value.Custom1);
        WriteKeyValue(context.Writer, value.Custom2);

        context.Writer.WriteEndDocument();
    }

    private void WriteKeyValue(IBsonWriter writer, KeyValuePair<string, double> kv)
    {
        writer.WriteName(kv.Key);
        writer.WriteDouble(kv.Value);
    }

    public override UserData Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        //TODO: implement data deserialization using context.Reader
        throw new NotImplementedException();
    }
}

要使其正常工作,您还需要以某种方式注册我们的 UserDataSerializerIBsonSerializationProvider 是实现该目标的最简单方法。

public class UserDataSerializationProvider : IBsonSerializationProvider
{
    public IBsonSerializer GetSerializer(Type type)
    {
        if (type == typeof(UserData)) return new UserDataSerializer();
        return null;
    }
}

终于可以使用了。

//register our serialization provider
BsonSerializer.RegisterSerializationProvider(new UserDataSerializationProvider());

var userdata = new UserData();
var doc = userdata.ToBsonDocument();

结果如下:

{ "Id" : 100, "Name" : "Superuser", "HelloWorld1" : 1.0, "HelloWorld2" : 2.0 }

您可能还想实现 UserDataSerializer.Deserialize() 方法以提供向后转换。可以使用 context.Reader.

以相同的方式完成

可以找到有关自定义序列化过程的更多信息 here