【问题标题】:How to Serialize a Collection of Interface Objects Using Protobuf-Net如何使用 Protobuf-Net 序列化接口对象的集合
【发布时间】:2015-07-08 22:05:30
【问题描述】:

我有以下类定义:

[ProtoInclude(2, typeof(Foo))]
public interface IFoo
{
    double Bar { get; }
}



[ProtoContract]
public class Foo : IFoo
{
    [ProtoMember(1)]
    private double _bar
    {
        get { return Bar / 10; }
        set { Bar = 10 * value; }
    }

    public double Bar { get; private set; }
}



[ProtoContract]
public class MyClass
{
    [ProtoMember(1, OverwriteList = true)]
    public IReadOnlyList<IFoo> Foos { get; private set; }
}

当我尝试使用 protobuf-net 序列化 MyClass 对象时,出现异常:

System.InvalidOperationException:无法为 MyNamespace.MyClass 准备序列化程序 ----> System.InvalidOperationException:没有为类型定义序列化程序:MyNamespace.IFoo

就我而言,我知道存储在 MyClass.Foos 中的项目的具体类型是 Foo。如何告诉 protobuf 在它看到类型 IFoo 的任何地方使用类型 Foo?或者,如何使它包含 Foo 作为可用于在集合中实现 IFoo 的类之一?

-- 编辑--

Sam 的回答非常接近,以至于它揭示了这种方法的另一个问题。即it is not possible to serialize a property of type IReadOnlyList<T> using protobuf-net。但是,有一个简单的解决方法,因为列表是在 MyClass 的构造函数中创建的。因此,MyClass 可以更改为以下内容:

[ProtoContract]
public class MyClass
{
    [ProtoMember(1, OverwriteList = true)]
    private List<IFoo> MutableFoos { get; set; }

    public IReadOnlyList<IFoo> Foos
    {
        get { return MutableFoos; }
    }
}

但是,MyClass 的序列化仍然失败,并显示消息“System.InvalidOperationException:未找到代理项的合适转换运算符:MyNamespace.IFoo / MyNamespace.Foo” .

【问题讨论】:

  • Sam 删除了他的答案(它没有编译),但由于我根据他的回答编辑了我的问题,我觉得总结他的解决方案以提供编辑的上下文可能很有用。从本质上讲,他的建议是通过在 MyClass 的静态构造函数中调用 RuntimeTypeModel.Default.Add(typeof(IFoo), false).SetSurrogate(typeof(Foo)) 来使用代理。
  • 我刚刚遇到了与代理 InvalidOperationException 相同的问题 - 你解决了吗?
  • @kirbatious 通常我会回答我自己的问题,如果我弄明白了,所以我的猜测是否定的。但是,我会在接下来的几天里仔细检查代码,看看我是否最终想出了如何让它工作。我会发布答案,或者在我确定后替换此评论。
  • @kirbatious 不幸的是,我最终放弃了这个。因为我只有一种IFoo 的实现类型,所以我只是让私有序列化成员使用底层的具体类。我添加了一个答案,解释了在我的情况下它是如何工作的。但是,我认为如果您使用列表中的每个成员(或包含类,如果您知道列表中的所有内容都具有同类型)。不过,我从未尝试过。
  • 我已经让它工作了。从您的原始问题和我能够实现的主要区别是我将ProtoContractProtoMember 放在界面上。但是我的实现相当复杂,先是使用接口,然后是泛型抽象类,然后是实现泛型抽象类的具体类。我使用 ProtoBuf 装饰器装配接口,ProtoInclude 具体类,并在适当的地方用 ProtoMember 装饰具体类。

标签: c# serialization protobuf-net


【解决方案1】:

在序列化成员中使用接口类的情况下,我永远无法使其工作。相反,我最终不得不将具体类作为列表成员类型。以下是最终对我有用的方法:

[ProtoContract]
public class MyClass
{
    [ProtoMember(1, OverwriteList = true)]
    private List<Foo> MutableFoos { get; set; }

    public IReadOnlyList<IFoo> Foos
    {
        get { return MutableFoos; }
    }
}

注意序列化成员中的类型是List&lt;Foo&gt;,而不是List&lt;IFoo&gt;。我从来不知道如何让后者工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2011-03-07
    相关资源
    最近更新 更多