与 protobuf-net 和 C# 的接口
Posted
技术标签:
【中文标题】与 protobuf-net 和 C# 的接口【英文标题】:Interfaces with protobuf-net and C# 【发布时间】:2011-11-18 12:10:28 【问题描述】:有谁知道为接口设置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。
顺便说一句:这个例子来自一组“通过测试的教训”,展示了如何为我的同事使用 protobuf-net 进行序列化。
感谢阅读:)
【问题讨论】:
为什么需要 DTO 的接口? @jgauffin:我只是在编写一些代码来了解 protobuf-net 的功能。第 5 课是关于接口的。 :) 【参考方案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 对象的接口支持是什么。
【讨论】:
是的,当您从未使用过反序列化程序时,似乎根对象存在问题。我已经编写了两个测试,一个使用包装器,一个没有包装器。如果带包装器的测试首先运行,则不带包装器的测试通过。但是如果没有包装器的测试首先运行,两个测试都会失败。 :? @graffic 最好的办法是记录一个错误,我会进行调查。很好奇。 好吧 :) 星期五晚上在这里,所以也许你必须等到星期一(无论如何我会尽力而为)。同时...我会接受您的正确回答以结束此问题。 马克,这个问题在 v2 中得到修复了吗?我正在使用 r480 并遇到同样的问题。 @Eric v1 从不支持接口。在 v2 中,它们仍然只作为 成员 工作。我必须解决这个问题...【参考方案2】:对我有用的最简单的解决方案是在序列化实际实例之前让 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
组合(缓存不会造成性能损失),它应该可以正常工作,无需额外配置。
【讨论】:
以上是关于与 protobuf-net 和 C# 的接口的主要内容,如果未能解决你的问题,请参考以下文章
协议缓冲区 c# (protobuf-net) Message::ByteSize
protobuf-net - 反引号、字典和 .proto 文件