我开发使用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序列化。
我需要知道的这两种方式是更好,如何实现它。
注 :我需要的是不修改接口,因为他们的项目不能包含任何外部参考的解决方案。
好了,试图让这个答案时,我发现了很多问题。
首先,MongoDB的C#驱动程序,不反序列化的接口 ,像克雷格·威尔逊在这个问题上的意见说,当有一些问题,并作为中所描述的问题页面 。
对于这个问题的安全实施,就像我之前说的,真的可能是一个自定义的BSON串行或一个特定的类图,使用BsonClassMap.RegisterClassMap
。
所以,我已经实现了一流的地图和问题依然存在。
反序列化时的问题:这个问题展望未来,我发现异常相关的驱动程序的另一个问题structs
。
我已经回滚该项目的初始状态(无类地图或自定义序列),改变了结构类型类类型, 和它的工作 。
在恢复,这个异常的错误是结构反序列化,不能与接口有关的反序列化。
无论如何,这是一个真正的问题,需要考虑更多的是比改善的bug,比如第一个问题是第二个问题。
您可以在这些链接的问题:
- https://jira.mongodb.org/browse/CSHARP-485
- https://jira.mongodb.org/browse/CSHARP-94
[BsonSerializer(typeof(ImpliedImplementationInterfaceSerializer<IReviewExpert, ReviewExpert>))] public IReviewExpert Expert { get; set; }
对我的作品
我们对蒙戈驱动程序的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;}
对代码的几个注意事项 - 所有这确实是地装载了相应的具体类型的串行器,然后通过对所有的序列化/反序列化调用,与相应的具体类型而不是接口。
它还检查该类型实际上是预期的类型,如果不只是找到该类型默认的序列。