Search code examples
c#protocol-buffersprotobuf-netproto

protobuf-net converts List<T> to List_T class when using .ToProto()


I have a requirement to take a library of C# classes that implement protobuf-net, and convert them into .proto files, which need to be converted using protoc into .py files. I understand that the .ToProto() function does this just fine, but I came up against an issue involving collections and generics when converting from .proto to .py files. When trying to serialize a list of DateTimes, for example I get the following error X.proto:64:13. "List_TimeSpan" is not defined. As this had not caused an issue upon serialization into a protobuf file, I wasn't aware of this situation at the time.

I am currently using proto-buf.net 2.3.2 for this project; it's the version some of my other work has been done with and I am aware that this could just be solved with a version upgrade. I'm just not sure if that is the answer with the digging I've done so far. If there's something else that I'm missing, I would truly appreciate any help that can be thrown my way.


Solution

  • If we consider:

    [ProtoContract]
    public class Foo {
        [ProtoMember(12)]
        public List<DateTime> Times { get; } = new List<DateTime>();
    }
    

    then GetProto<T>() in both v2.3.2 (the version mentioned in the question) and v2.4.4 (the current default version) generate:

    syntax = "proto2";
    import "protobuf-net/bcl.proto"; // schema for protobuf-net's handling of core .NET types
    
    message Foo {
       repeated .bcl.DateTime Times = 12;
    }
    

    So on the surface of it, it should already be just fine. If you're doing something more exotic (perhaps using a list in a dictionary value?), I'd be happy to help, but I'm going to need more of a clue as to what you're doing. Posting some C# that shows the thing you're seeing would be a great place to start.


    Note that when protobuf-net first came around, there was no agreed transmission format for date/time-like values, so protobuf-net made something up, but it turns out to not be a convenient fit for cross-platform work; the following is a hard breaking change (it is not data compatible), but if possible, I would strongly recommend the well-known format that Google added later:

    [ProtoContract]
    public class Foo {
        [ProtoMember(12, DataFormat = DataFormat.WellKnown)]
        public List<DateTime> Times { get; } = new List<DateTime>();
    }
    

    which generates:

    syntax = "proto2";
    import "google/protobuf/timestamp.proto";
    
    message Foo {
       repeated .google.protobuf.Timestamp Times = 12;
    }