当前位置 : 主页 > 大数据 > 区块链 >

使用protobuf序列化F#区分联合

来源:互联网 收集:自由互联 发布时间:2021-06-22
有没有办法让protobuf序列化/反序列化F#的歧视联盟? 我正在尝试使用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#编译器!

网友评论