Thanks @Martin_Plante for your questions.
NullableSerializer: Yes, its a nullable version for value serializers.
Custom value on null: There is no quick configuration option for that. The only way is to implement a custom serializer to handle the null values.
One way would the mentioned approach of having multiple serializers with hardcoded values like BooleanDefaultTrueSerializer.
More complex and generic approach would be augmenting an existing value serializer and configuring it with a custom value. Custom value configuration could be done via an attribute, which can be also used to configure the default value on missing data. Partial example:
public class MyClass
{
[CustomSerializerOption<int>(DefaultValue = 11)]
[BsonSerializer(typeof(CustomValueOnNull<int>))]
public int A { get; set; }
[CustomSerializerOption<bool>(DefaultValue = true)]
[BsonSerializer(typeof(CustomValueOnNull<bool>))]
public bool T { get; set; }
}
public sealed class CustomSerializerOption<T> : Attribute, IBsonMemberMapAttribute
where T : struct
{
public CustomSerializerOption()
{
DefaultValue = default;
}
public T DefaultValue { get; set; }
public void Apply(BsonMemberMap memberMap)
{
var serializer = memberMap.GetSerializer();
var serializer2 = ApplySerializer(serializer);
memberMap.SetSerializer(serializer2);
memberMap.SetDefaultValue(DefaultValue);
}
private IBsonSerializer ApplySerializer(IBsonSerializer serializer)
{
if (serializer is CustomValueOnNull<T> customSerializer)
{
return customSerializer.WithDefaultValue(DefaultValue);
}
throw new InvalidOperationException();
}
}
public sealed class CustomValueOnNull<T> : IBsonSerializer<T>
where T : struct
{
private readonly IBsonSerializer<T> _valueSerializer;
private readonly T _defaultValue;
public CustomValueOnNull()
: this(default, BsonSerializer.SerializerRegistry)
{
}
public CustomValueOnNull(T defaultValue, IBsonSerializer<T> valueSerializer)
{
if (valueSerializer == null)
{
throw new ArgumentNullException(nameof(valueSerializer));
}
_valueSerializer = valueSerializer;
_defaultValue = defaultValue;
}
public T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
if (bsonType == BsonType.Null)
{
bsonReader.ReadNull();
return _defaultValue;
}
else
{
return _valueSerializer.Deserialize(context);
}
}
public CustomValueOnNull<T> WithDefaultValue(T defaultValue) =>
new(defaultValue, _valueSerializer);
....
}