Deserialize object as an interface with MongoDB C# Driver

前端 未结 3 1957
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-17 16:52

I am developing a project that uses MongoDB (with C# driver) and DDD.

I have a class (aggregate) which have a property whi

3条回答
  •  無奈伤痛
    2020-12-17 16:55

    We are on the 1.x branch of mongo drivers and that sadly doesn't have the ImpliedImplementationInterfaceSerializer that was suggested by Robert Baker which seems to be otherwise a good solution. To this end I created my own serializer that allows you to specify a confcrete type for an interface member.

    public class ConcreteTypeSerializer : BsonBaseSerializer where TImplementation : TInterface
    {
        private readonly Lazy _lazyImplementationSerializer;
    
        public ConcreteTypeSerializer()
        {
            var serializer = BsonSerializer.LookupSerializer(typeof(TImplementation));
    
            _lazyImplementationSerializer = new Lazy(() => serializer);
        }
    
        public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
        {
            if (bsonReader.GetCurrentBsonType() == BsonType.Null)
            {
                bsonReader.ReadNull();
                return default(TInterface);
            }
            else
            {
                return _lazyImplementationSerializer.Value.Deserialize(bsonReader, nominalType, typeof(TImplementation), options);
            }
        }
    
        public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
        {
            if (value == null)
            {
                bsonWriter.WriteNull();
            }
            else
            {
                var actualType = value.GetType();
                if (actualType == typeof(TImplementation))
                {
                    _lazyImplementationSerializer.Value.Serialize(bsonWriter, nominalType, (TImplementation)value, options);
                }
                else
                {
                    var serializer = BsonSerializer.LookupSerializer(actualType);
                    serializer.Serialize(bsonWriter, nominalType, value, options);
                }
            }
        }
    }
    

    Usage is as follows:

    [BsonSerializer(typeof(ConcreteTypeSerializer))]
    public IMyInterface MyProperty {get; set;}
    

    A few notes on the code - all it really does is lazily loads the serializer for the appropriate concrete type and then passes on all the serialize/deserialize calls to that with the appropriate concrete type instead of the interface.

    It also checks that the type is actually of the expected type and if not just finds the default serializer for the type.

提交回复
热议问题