【问题标题】:Serializing custom IEnumerable<T> as field not working将自定义 IEnumerable<T> 序列化为字段不起作用
【发布时间】:2015-04-14 20:16:44
【问题描述】:

我有一个如下所示的自定义集合:

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 中使用属性并通过代码使 ASpecialReadOnlyCollection 可序列化,那么一切正常。

我做错了什么吗?我怎样才能解决这个问题? (可能最简单的答案是使用属性......但我真的想避免使用属性)。

tl;dr:如何通过 RuntimeTypeModel 使用 protobuf-net 序列化一个具有不应被视为列表 (IgnoreListHandling = true) 作为成员的 IEnumerable 成员的类。

【问题讨论】:

    标签: c# serialization protobuf-net


    【解决方案1】:

    protobuf-net 支持一系列列表模式;在您的情况下,它正在尝试使用 IEnumerable&lt;T&gt;/GetEnumerator()Add(T) 模式。它需要两者IEnumerable&lt;T&gt;/GetEnumerator() 用于序列化,Add(T) 用于反序列化。如果您的自定义集合没有明显的 Add(T) 方法,那么 protobuf-net 将拒绝使用该集合,因为 它永远无法反序列化。这就是方法告诉你的。

    解决这个问题的唯一方法可能是使用可变 DTO 模型,而不是这个只读集合。 protobuf-net 支持隐式类型转换之类的东西,但不适用于这种情况。

    【讨论】:

    • 所以我想我误解了IgnoreListHandling 的作用。该属性不是告诉 protobuf 该类应该作为普通类而不是列表来处理吗?我觉得奇怪的是,通过使用属性进行装饰,它工作得很好。事实上,似乎有问题的是我将ContainerOfA 添加到模型中的方式,而不是IEnumerable 本身。
    • 此外,序列化列表也可以正常工作。导致它停止工作的原因是试图将其序列化为其他对象中的字段。
    • @SantiagoCerónUribe 是“其他对象中的字段” - 是的,根对象的处理方式略有不同 - 不理想,但是:它只看起来像 IEnumerable&lt;T&gt;IgnoreListHandling 确实告诉它把它当作叶子,而不是列表。可能是我误解了这个问题:我明天可以睡一觉再读一遍吗?
    • 可能是(如果您误解了,那么我还有希望!)。非常感谢您的快速帮助。
    • @SantiagoCerónUribe 对于使用代理序列化类型代替ContainerOfA,您感觉如何?即一种看起来相似的类型(但可能带有List&lt;A&gt; 字段),可以根据需要自动前后交换?该库支持这种用法。如果足够的话,我明天可以做一个例子。从所有外观来看:您将序列化/反序列化 ContainerOfA
    猜你喜欢
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 1970-01-01
    • 2010-11-27
    相关资源
    最近更新 更多