Serializing F# discriminated unions with protobuf

前端 未结 3 987
有刺的猬
有刺的猬 2020-12-16 04:27

Is there some way to get protobuf to serialize/deserialize F#\'s discriminated unions?

I\'m trying to serialize messages with protobuf. Messages are F# records and d

3条回答
  •  伪装坚强ぢ
    2020-12-16 05:03

    I've played with your very helpful generated output, and it looks like basically everything works - except the Message.MessageA sub-types. These very nearly work - they are essentially the same as the "auto-tuple" code (a constructor that matches all members), except that auto-tuples doesn't currently apply to sub-types.

    I think it should be possible to tweak the code to work automatically, by extending the auto-tuple code to work in this scenario (I'm trying to think of any possible bad side-effects of that, but I'm not seeing any). I don't have a specific time-frame, as I need to balance time between multiple projects and a full-time day-job, and a family, and volunteer work, and (etc etc).

    In the short term, the following C# is sufficient to make it work, but I don't expect this will be an attractive option:

    RuntimeTypeModel.Default[typeof(Message).GetNestedType("MessageA")]
                    .Add("item").UseConstructor = false;
    RuntimeTypeModel.Default[typeof(Message).GetNestedType("MessageB")]
                    .Add("item").UseConstructor = false;
    

    As an aside, the attributes here are unhelpful and should be avoided:

    | [] MessageA of MessageA
    | [] MessageB of MessageB
    

    If they did anything, they would be duplicating the intent of . If it is more convenient to specify them there, that might be interesting, though. But what I find really interesting about that is that the F# compiler completely ignores the AttributeUsageAttribute, which for [ProtoMember] is:

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
        AllowMultiple = false, Inherited = true)]
    public class ProtoMemberAttribute {...}
    

    Yes the F# compiler clearly stuck that (illegally) on a method:

    [ProtoMember(1)]
    [CompilationMapping(SourceConstructFlags.UnionCase, 0)]
    public static ProtoBufTests.Message NewMessageA(ProtoBufTests.MessageA item)
    

    naughty F# compiler!

提交回复
热议问题