反序列化对象作为与MongoDB的C#驱动的接口(Deserialize object as an

2019-07-18 20:51发布

我开发使用MongoDB的 (用C#驱动程序)和DDD的项目。

我有一个类( 聚集 ),其具有的特性,其类型是一个接口。 在另一类,我已经实现了这个接口。 此类具有另一特性,其类型是一个接口,并设置好的与另一实现类。

下面的代码解释更好:

// Interfaces
public interface IUser {
    Guid Id { get; set;}
    IPartner Partner{ get; set; }
}

public interface IPartner {
    IPhone Mobile { get; set; }
}

public interface IPhone {
    string number { get; set; }
}

// Implemented Classes
public class User: IUser {
    [BsonId(IdGenerator = typeof(GuidGenerator))]
    public Guid Id { get; set; }

    [BsonIgnoreIfNull]
    public IPartner Partner { get; set; }
}

public struct Partner : IPartner {
    public IPhone Mobile { get; set; }
}

public struct Phone : IPhone {
    public string Number { get; set; }
}

那么,当我调用MongoCollection<User>.Insert()的方法,它引发两个例外:

System.IO.FileFormatException:反序列化类。用户的合作伙伴属性时发生错误:值类。移动无法反序列化:反序列化类.Partner的电话属性时发生错误。 ---> System.IO.FileFormatException:值类.Phone无法反序列化:反序列化类.Partner的移动属性时发生错误。 ---> MongoDB.Bson.BsonSerializationException:值类.Phone无法反序列化。

于是,我在网上搜索了探索如何反序列化类型的接口,我想我要如何做到这一点:与映射铸造属性,使用BsonClassMap.RegisterClassMap或编写自定义的BSON序列化。

我需要知道的这两种方式是更好,如何实现它。

:我需要的是不修改接口,因为他们的项目不能包含任何外部参考的解决方案。

Answer 1:

好了,试图让这个答案时,我发现了很多问题。

首先,MongoDB的C#驱动程序,不反序列化的接口 ,像克雷格·威尔逊在这个问题上的意见说,当有一些问题,并作为中所描述的问题页面 。

对于这个问题的安全实施,就像我之前说的,真的可能是一个自定义的BSON串行或一个特定的类图,使用BsonClassMap.RegisterClassMap

所以,我已经实现了一流的地图和问题依然存在。

反序列化时的问题:这个问题展望未来,我发现异常相关的驱动程序的另一个问题structs

我已经回滚该项目的初始状态(无类地图或自定义序列),改变了结构类型类类型, 和它的工作

在恢复,这个异常的错误是结构反序列化,不能与接口有关的反序列化。


无论如何,这是一个真正的问题,需要考虑更多的是比改善的bug,比如第一个问题是第二个问题。

您可以在这些链接的问题:

  • https://jira.mongodb.org/browse/CSHARP-485
  • https://jira.mongodb.org/browse/CSHARP-94


Answer 2:

[BsonSerializer(typeof(ImpliedImplementationInterfaceSerializer<IReviewExpert, ReviewExpert>))] public IReviewExpert Expert { get; set; }

对我的作品



Answer 3:

我们对蒙戈驱动程序的1.x的分支,可悲的是没有ImpliedImplementationInterfaceSerializer ,是由罗伯特·贝克这似乎是另有一个很好的解决方案建议。 为此我创建了自己的串行器,允许你指定的接口部件confcrete类型。

public class ConcreteTypeSerializer<TInterface, TImplementation> : BsonBaseSerializer where TImplementation : TInterface
{
    private readonly Lazy<IBsonSerializer> _lazyImplementationSerializer;

    public ConcreteTypeSerializer()
    {
        var serializer = BsonSerializer.LookupSerializer(typeof(TImplementation));

        _lazyImplementationSerializer = new Lazy<IBsonSerializer>(() => 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);
            }
        }
    }
}

用法如下:

[BsonSerializer(typeof(ConcreteTypeSerializer<IMyInterface,MyClass>))]
public IMyInterface MyProperty {get; set;}

对代码的几个注意事项 - 所有这确实是地装载了相应的具体类型的串行器,然后通过对所有的序列化/反序列化调用,与相应的具体类型而不是接口。

它还检查该类型实际上是预期的类型,如果不只是找到该类型默认的序列。



文章来源: Deserialize object as an interface with MongoDB C# Driver