自定义序列化程序,处理MongoDb的可空类型和非可空类型

时间:2018-02-08 15:52:40

标签: c# mongodb serialization mongodb-.net-driver

我需要使用IBsonSerializer实现自定义序列化程序。

这就是我所做的:

internal class MyCustomDateTimeSerializer : IBsonSerializer
{
   public object Deserialize(BsonDeserializationContext context, 
         BsonDeserializationArgs args)
   {
       // Deserialization logic
   }

   public void Serialize(BsonSerializationContext context, 
         BsonSerializationArgs args, object value)
   {
       // Serialization logic
   }

   public Type ValueType => typeof(DateTime);
}

然后在BsonSerializerAttribute:

中使用它
[BsonSerializer(typeof(MyCustomDateTimeSerializer))]

我的问题是我想序列化/反序列化DateTime和Nullable DateTime。

我的CustomSerializer的ValueType设置为typeof(DateTime),因为我得到了如下例外:

  

序列化程序的值类型是System.DateTime,与成员类型System.Nullable`1 [[System.DateTime ..

>不匹配

我没有找到任何解决此问题的方法。 当然,我可以为Nullable DateTime和DateTime创建两个不同的类,但也许还有另一个选项?

1 个答案:

答案 0 :(得分:2)

如果你检查MongoDB.Bson库中SetSerializer方法的源代码,你会发现它对成员类型的检查非常简单:

if (serializer.ValueType != _memberType)
{
    var message = string.Format("Value type of serializer is {0} and does not match member type {1}.", serializer.ValueType.FullName, _memberType.FullName);
    throw new ArgumentException(message, "serializer");
}

代码检查类型相等,并且无法欺骗它并认为DateTimeNullable<DateTime>相等。

但是有一个解决方案可以用来拥有一个序列化程序类并避免重复代码。您可以使序列化程序成为泛型类,并强制它仅接受DateTimeNullable<DateTime>作为类型参数。 这是一个示例:

internal class MyCustomDateTimeSerializer<TDateTime> : IBsonSerializer
{
    static MyCustomDateTimeSerializer()
    {
        if (typeof(TDateTime) != typeof(DateTime) && typeof(TDateTime) != typeof(DateTime?))
        {
            throw new InvalidOperationException($"MyCustomDateTimeSerializer could be used only with {nameof(DateTime)} or {nameof(Nullable<DateTime>)}");
        }
    }

    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        // Deserialization logic
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        // Serialization logic
    }

    public Type ValueType => typeof(TDateTime);
}

public class SomeDocument
{
    // ...

    [BsonSerializer(typeof(MyCustomDateTimeSerializer<DateTime>))]
    public DateTime Date1 { get; set; }

    [BsonSerializer(typeof(MyCustomDateTimeSerializer<DateTime?>))]
    public DateTime? Date2 { get; set; }
}