MongoDB - override default Serializer for a C# primitive type

You can definitely do this, you just have to get the timing right. When the driver starts up there are no serializers registered. When it needs a serializer, it looks it up in the dictionary where it keeps track of the serializers it knows about (i.e. the ones that have been registered). Only it it can't find one in the dictionary does it start figuring out where to get one (including calling the serialization providers) and if it finds one it registers it.

The limitation in RegisterSerializer is there so that you can't replace an existing serializer that has already been used. But that doesn't mean you can't register your own if you do it early enough.

However, keep in mind that registering a serializer is a global operation, so if you register a custom serializer for double it will be used for all doubles, which could lead to unexpected results!

Anyway, you could write the custom serializer something like this:

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);
    }
}

And register it like this:

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

You could test it using the following class:

public class C
{
    public int Id;
    public double X;
}

and this code:

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);

You can also use your own serialization provider to tell Mongo which serializer to use for certain types, which I ended up doing to mitigate some of the timing issues mentioned when trying to override existing serializers. Here's an example of a serialisation provider that overrides how to serialize decimals:

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
    }
}

If you return null from your custom serialization provider, it will fall back to using Mongo's default serialization provider.

Once you've written your provider, you just need to register it:

BsonSerializer.RegisterSerializationProvider(new CustomSerializationProvider());