我有一个自定义集合,如下所示:
class SpecialReadOnlyCollection<T> : IReadOnlyCollection<T>{
private readonly List<T> entries;
public SpecialReadOnlyCollection(IEnumerable<T> source){
entries = new List<T>(source);
}
...
}
那(除其他外)包装了一个列表,但没有提供Add
方法。
现在我有两个其他类:
class A{
public string Name;
public int Value;
}
class ContainerOfA{
public SpecialReadOnlyCollection<A> list;
public ContainerOfA(IEnumerable<A> source){
this.list = new SpecialReadOnlyCollection<A>(source);
}
}
我想序列化ContainerOfA
。由于我不喜欢属性,因此我就是如何构建模型并尝试序列化的。
// Make A serializable
var metaType = Model.Add(typeof(A),true);
metaType.AddField(1,"Name");
metaType.AddField(2,"Value");
metaType.UseConstructor = false;
// Make SpecialCollection serializable
Model.Add(typeof(SpecialReadOnlyCollection<A>),true).AddField(1,"entries");
Model[typeof(SpecialReadOnlyCollection<A>)].IgnoreListHandling = true;
Model[typeof(SpecialReadOnlyCollection<A>)].UseConstructor = false;
// Make container serializable
Model.Add(typeof(ContainerOfA),true).AddField(1,"list");
Model[typeof(ContainerOfA)].UseConstructor = false;
// Initialize the container
A a = new A{Name ="Name", Value =1};
A[] arr = {a};
var container = new ContainerOfA(arr);
// Try and serialize ....
Model.DeepClone(container);
然而,当我尝试序列化时,我得到一个例外:
Unable to resolve a suitable Add method for SpecialReadOnlyCollection[A]
我觉得奇怪的是,如果我尝试序列化列表,它可以正常工作:
Model.DeepClone(container.list);
如果我不是在代码使用属性中构建模型,那么一切正常。事实上,如果我仅在ContainerOfA
中使用属性并使A
和SpecialReadOnlyCollection
可通过代码进行序列化,则一切正常。
我做错了吗?我怎么能绕过这个? (可能最简单的答案是使用属性......但我真的想避免属性)。
tl; dr:如何通过RuntimeTypeModel
使用protobuf-net序列化一个类,该类具有不应被视为列表的IEnumerable成员(IgnoreListHandling = true
)。
答案 0 :(得分:0)
protobuf-net支持一系列列表模式;在您的情况下,它正在尝试使用IEnumerable<T>/GetEnumerator()
和Add(T)
模式。它需要两者:IEnumerable<T>/GetEnumerator()
用于序列化,Add(T)
用于反序列化。如果您的自定义集合没有明显的Add(T)
方法,那么protobuf-net将拒绝使用该集合,因为它将无法反序列化。这就是方法告诉你的。
解决这个问题的唯一方法可能是使用可变DTO模型,而不是这个只读集合。 是类似于protobuf-net支持的隐式类型转换之类的东西,但不支持这种情况。