将对象反序列化为MongoDB C#Driver的接口

我正在开发一个使用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.Insert()方法时,它抛出两个exception:

System.IO.FileFormatException:反序列化类的.perser的Partner属性时发生错误:反序列化类的Phone属性时发生错误.Partner:值类.Mobile无法反序列化。 —> System.IO.FileFormatException:反序列化类的.Partner的Mobile属性时发生错误:值类.Phone无法反序列化。 —> MongoDB.Bson.BsonSerializationException:值类.Phone无法反序列化。

然后,我在互联网上搜索了如何将类型反序列化为接口,我想我必须要做的方法:使用BsonClassMap.RegisterClassMap或编写自定义BSON序列化器来使用BsonClassMap.RegisterClassMap来映射属性。

我需要知道这两种方式中哪一种更好,以及如何实现它。

注意 :我需要一个不修改接口的解决方案,因为他们的项目不能包含任何外部引用。

好吧,我在试图得到这个答案时发现了很多问题。

首先,MongoDB C#驱动程序在反序列化接口时确实存在一些问题,如Craig Wilson在此问题评论中所述, 以及问题页面中所述 。

像我之前所说的,这个问题的安全实现可能是使用BsonClassMap.RegisterClassMap的自定义BSON序列化程序或特定的类映射。

所以,我已经实现了类映射并且问题仍然存在。

期待这个问题,我发现exception与驱动程序的另一个问题有关:反序列化structs时的问题

我已将项目回滚到初始状态(没有类映射或自定义序列化程序)并将结构类型更改为类类型, 并且它可以工作

在恢复中,此exception错误与结构反序列化有关,而不与接口反序列化有关。


无论如何,这是一个真正的问题,第二个问题需要被视为一个错误而不是改进,就像第一个问题一样。

您可以在以下链接中找到问题:

[BsonSerializer(typeof(ImpliedImplementationInterfaceSerializer))] public IReviewExpert Expert { get; set; }

适合我

我们在mongo驱动程序的1.x分支上,遗憾的是没有Robert Baker建议的ImpliedImplementationInterfaceSerializer ,这似乎是一个很好的解决方案。 为此,我创建了自己的序列化程序,允许您为接口成员指定confcrete类型。

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

用法如下:

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

关于代码的一些注意事项 – 它真正做的就是懒惰地为相应的具体类型加载序列化程序,然后将所有序列化/反序列化调用传递给具有适当具体类型而不是接口的序列化。

它还会检查该类型实际上是否为预期类型,如果不是,则只查找该类型的默认序列化程序。