有没有办法让protobuf序列化/反序列化F#的歧视联盟? 我正在尝试使用protobuf序列化消息.消息是F#记录和受歧视的联合. 序列化似乎适用于记录,但我不能让它与歧视的联合工作. 在下面的代
我正在尝试使用protobuf序列化消息.消息是F#记录和受歧视的联合.
序列化似乎适用于记录,但我不能让它与歧视的联合工作.
在下面的代码中,测试testMessageA和testMessageB是绿色的.测试testMessageDU为红色.
module ProtoBufSerialization open FsUnit open NUnit.Framework open ProtoBuf type MessageA = { X: string; Y: int; } type MessageB = { A: string; B: string; } type Message = | MessageA of MessageA | MessageB of MessageB let serialize msg = use ms = new System.IO.MemoryStream() Serializer.SerializeWithLengthPrefix(ms, msg, PrefixStyle.Fixed32) ms.ToArray() let deserialize<'TMessage> bytes = use ms = new System.IO.MemoryStream(buffer=bytes) Serializer.DeserializeWithLengthPrefix<'TMessage>(ms, PrefixStyle.Fixed32) [<Test>] let testMessageA() = let msg = {X="foo"; Y=32} msg |> serialize |> deserialize<MessageA> |> should equal msg [<Test>] let testMessageB() = let msg = {A="bar"; B="baz"} msg |> serialize |> deserialize<MessageB> |> should equal msg [<Test>] let testMessageDU() = let msg = MessageA {X="foo"; Y=32} msg |> serialize |> deserialize<Message> |> should equal msg
我尝试在类型Message上添加ProtoInclude和KnownType等不同的属性,在MessageA和MessageB类型上添加CLIMutable,但似乎没有任何帮助.
我不想将我的DU映射到类来使序列化工作……
我已经使用了非常有用的生成输出,看起来基本上一切正常 – 除了Message.MessageA子类型.这些非常接近 – 它们基本上与“自动元组”代码(匹配所有成员的构造函数)相同,除了自动元组当前不适用于子类型.我认为应该可以调整代码以自动工作,通过扩展自动元组代码在这种情况下工作(我试图想到任何可能的坏副作用,但我没有看到任何).我没有具体的时间框架,因为我需要在多个项目和全职日间工作,家庭,志愿者工作和(等等)之间平衡时间.
在短期内,以下C#足以使其工作,但我不认为这将是一个有吸引力的选择:
RuntimeTypeModel.Default[typeof(Message).GetNestedType("MessageA")] .Add("item").UseConstructor = false; RuntimeTypeModel.Default[typeof(Message).GetNestedType("MessageB")] .Add("item").UseConstructor = false;
顺便说一句,这里的属性是无益的,应该避免:
| [<ProtoMember(1)>] MessageA of MessageA | [<ProtoMember(2)>] MessageB of MessageB
如果他们做了什么,他们将重复< ProtoInclude(n)>的意图.如果在那里指定它们更方便,那可能会很有趣.但我觉得非常有趣的是,F#编译器完全忽略了AttributeUsageAttribute,对于[ProtoMember],它是:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] public class ProtoMemberAttribute {...}
是的,F#编译器明显地将其(非法)粘贴在一个方法上:
[ProtoMember(1)] [CompilationMapping(SourceConstructFlags.UnionCase, 0)] public static ProtoBufTests.Message NewMessageA(ProtoBufTests.MessageA item)
顽皮的F#编译器!