与protobuf-net和C#的接口

时间:2011-11-18 12:10:28

标签: c# .net protobuf-net

有人知道为接口设置 ProtoContract 的正确方法是什么?

我得到以下异常“仅使用属性生成序列化程序后无法更改类型”。

使用的代码:

    [ProtoContract]
    public class Lesson5TestClass2 : ILesson5TestInteface1
    {
        [ProtoMember(1)]
        public string Name { get; set; }
        [ProtoMember(2)]
        public string Phone { get; set; }
    }

    [ProtoContract]
    [ProtoInclude(1000, typeof(Lesson5TestClass2))]
    public interface ILesson5TestInteface1
    {
        [ProtoMember(1)]
        string Name { get; set; }
        [ProtoMember(2)]
        string Phone { get; set; }
    }

只有添加以下设置,我才能反序列化:

  RuntimeTypeModel.Default.Add(typeof (ILesson5TestInteface1), true)
      .AddSubType(50, typeof(Lesson5TestClass2));

我真的很想只使用属性配置它。

我正在使用NuGet的protobuf-net r470。

BTW:这个例子来自一组“通过测试的教训”,展示了如何使用protobuf-net为我的同事进行序列化。

感谢阅读:)

2 个答案:

答案 0 :(得分:1)

有趣;是的,看起来有些东西在那里。但是,在作为成员公开时工作,即

[ProtoContract]
class Wrapper
{
    [ProtoMember(1)]
    public ILesson5TestInteface1 Content { get; set; }
}
static class Program
{
    static void Main()
    {
        Wrapper obj = new Wrapper
        {
            Content = new Lesson5TestClass2()
        }, clone;
        using(var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, obj);
            ms.Position = 0;
            clone = Serializer.Deserialize<Wrapper>(ms);
        }
        // here clone.Content *is* a Lesson5TestClass2 instance
    }
}

我将不得不查看界面支持的内容是 root 对象。

答案 1 :(得分:0)

对我有用的最简单的解决方案是在序列化实际实例之前让 Protobuf 知道接口。

var obj = new Lesson5TestClass2();
using var ms = new MemoryStream();

// vvv - Add this line
Serializer.PrepareSerializer<ILesson5TestInteface1>();

Serializer.Serialize(ms, obj);
ms.Position = 0;
var clone = Serializer.Deserialize<ILesson5TestInteface1>(ms);

我猜这个调用使 Protobuf 将 Lesson5TestClass2 序列化为 ILesson5TestInteface1 的实例,否则它不会这样做,因为它没有机会知道 ILesson5TestInteface1

如果您按照另一个答案的建议使用包装器 class,这可能也会发生这种情况(然后 Protobuf 知道该接口,因为它是在序列化之前检查的一种属性类型)。

<块引用>

我真的很想只使用属性来配置它。

这个解决方案几乎就是您想要的,但仍然需要为每个接口调用一次 PrepareSerializer(这比 RuntimeTypeModel.Default.Add 更好,因为每个实现调用一次)。但是,您可以轻松地创建一个辅助方法来每次调用 PrepareSerializer + Serialize 组合(因为它被缓存不会有性能损失)并且它应该可以正常工作,不需要额外的配置。