gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 14:58:20 24 4
gpt4 key购买 nike

有没有办法让 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# 编译器!

关于f# - 使用 protobuf 序列化 F# 区分联合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24884814/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com