MongoDB - 覆盖C#基元类型的默认Serializer

cir*_*rus 8 mongodb-.net-driver

我想将C#Doubles的表示形式更改为圆形Int64,并在MongoDB的序列化C#驱动程序堆栈中使用四位小数位移.换句话说,存储(双)29.99为(Int64)299900

我希望这对我的应用程序透明.我已经看过自定义序列化程序,但我不想覆盖所有内容,然后将带有回退的Type打开到默认值,因为这有点乱.

我可以看到RegisterSerializer()不允许我为现有类型添加一个,并且BsonDefaultSerializationProvider有一个原始序列化器的静态列表,它被标记为内部私有成员,所以我不能轻易地子类化.

我还可以看到代表双胞胎代表Int64是可能的,但这是演员而不是转换.我需要在两个序列化方向上基本上进行转换和转换.

我希望我可以给默认的序列化程序一个自定义序列化程序来覆盖它自己的一个,但这意味着一个肮脏的黑客.

我错过了一个非常简单的方法吗?

Rob*_*tam 23

你绝对可以做到这一点,你只需要正确的时机.当驱动程序启动时,没有注册序列化程序.当它需要一个序列化程序时,它会在字典中查找它跟踪它所知道的序列化程序(即已经注册的序列化程序).只有它在字典中找不到它才会开始找出从哪里获得一个(包括调用序列化提供者),如果找到它就注册它.

RegisterSerializer中存在限制,因此您无法替换已使用的现有序列化程序.但这并不意味着如果你做得足够早,就不能注册自己的.

但是,请记住注册序列化程序是一个全局操作,因此如果您为双重注册自定义序列化程序,它将用于所有双打,这可能会导致意外的结果!

无论如何,您可以编写自定义序列化程序,如下所示:

public class CustomDoubleSerializer : BsonBaseSerializer
{
    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
    {
        var rep = bsonReader.ReadInt64();
        return rep / 100.0;
    }

    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
    {
        var rep = (long)((double)value * 100);
        bsonWriter.WriteInt64(rep);
    }
}
Run Code Online (Sandbox Code Playgroud)

并注册如下:

BsonSerializer.RegisterSerializer(typeof(double), new CustomDoubleSerializer());
Run Code Online (Sandbox Code Playgroud)

您可以使用以下类测试它:

public class C
{
    public int Id;
    public double X;
}
Run Code Online (Sandbox Code Playgroud)

而这段代码:

BsonSerializer.RegisterSerializer(typeof(double), new CustomDoubleSerializer());

var c = new C { Id = 1, X = 29.99 };
var json = c.ToJson();
Console.WriteLine(json);

var r = BsonSerializer.Deserialize<C>(json);
Console.WriteLine(r.X);
Run Code Online (Sandbox Code Playgroud)


adr*_*ian 5

您还可以使用您自己的序列化提供程序来告诉 Mongo 对某些类型使用哪个序列化程序,我最终这样做是为了缓解在尝试覆盖现有序列化程序时提到的一些计时问题。这是一个序列化提供程序的示例,它覆盖了如何序列化小数:

public class CustomSerializationProvider : IBsonSerializationProvider
{
    public IBsonSerializer GetSerializer(Type type)
    {
        if (type == typeof(decimal)) return new DecimalSerializer(BsonType.Decimal128);

        return null; // falls back to Mongo defaults
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您null从自定义序列化提供程序返回,它将回退到使用 Mongo 的默认序列化提供程序。

一旦你编写了你的​​提供者,你只需要注册它:

BsonSerializer.RegisterSerializationProvider(new CustomSerializationProvider());
Run Code Online (Sandbox Code Playgroud)