1

我知道 protobuf 不支持继承,并且由于我在另一端使用 protoc-c,所以我也不想使用任何扩展。但是,我坚持使用依赖于继承的 C# 模型:

class Header {
     public int version { get; set; }
}

class Message : Header {
     public String message { get; set; }
}

我试图将继承转换为有线格式的封装,如下所示:

[ProtoContract]
class Header {
     [ProtoMember(1)]
     public int version { get; set; }
}

[ProtoContract]
class Message : Header {
     [ProtoMember(1)]
     public Header Header { get { return this; } set { } }

     [ProtoMember(2)]
     public String Message { get; set; }
}

然后我收到“意外的子类型”错误提示我: 为什么我必须使用 [ProtoInclude]?

我觉得我的情况与上述问题的情况不同,所以想再次询问我的具体情况,我试图从内到外继承,如果没有ProtoInclude,这是否不可能?

如果没有,我将如何在 v2 中做到这一点?

----- 已编辑 ------

我在 C(使用 protobuf-c)端的 proto 文件是这样的:

message Header {
    optional int32 version = 1;
}

message Message {
    optional Header header = 1;
    optional string message = 2;
}

我不想将 Message 放在 Header 中,也不想使用网络继承功能。这种格式使我能够轻松地将内容添加到 Header 消息中,而无需更改 Message 消息。

4

1 回答 1

0

通过编辑:不,不直接支持该场景 - protobuf-net 高度了解继承,并且不太愿意忽略它。这似乎是一个不寻常的情况,我并不急于添加它,而且我认为return this;getter 和 no-op setter 会导致额外的下游并发症(不是错误,因为它预计不会支持),这可能很难纠正。

我建议使用与您要表示的结构相似的模型。如果这不能直接实现,您可以使用代理。以下工作并保留了您预期的线结构和现有的类型继承:

using ProtoBuf;
using ProtoBuf.Meta;

// DTO model - maps directly to the wire layout
[ProtoContract]
class HeaderDto
{
    [ProtoMember(1)]
    public int Version { get; set; }
}

[ProtoContract]
class MessageDto
{
    [ProtoMember(1)]
    public HeaderDto Header { get { return header;}}
    private readonly HeaderDto header = new HeaderDto();

    [ProtoMember(2)]
    public string Message { get; set; }

    // the operators (implicit or explicit) are used to map between the
    // primary type (Message) and the surrogate type (MessageDto)
    public static implicit operator Message(MessageDto value)
    {
        return value == null ? null : new Message {
            version = value.Header.Version, message = value.Message };
    }
    public static implicit operator MessageDto(Message value)
    {
        return value == null ? null : new MessageDto {
            Message = value.message, Header = { Version = value.version } };
    }
}

// domain model
class Header
{
    public int version { get; set; }
}

class Message : Header
{
    public string message { get; set; }
}

// example
static class Program
{
    static void Main()
    {
        // configure the surrogate
        RuntimeTypeModel.Default.Add(typeof(Message), false)
                        .SetSurrogate(typeof(MessageDto));
        Message msg = new Message { version = 1, message = "abc" };
        var obj = Serializer.DeepClone(msg);
    }
}
于 2012-08-14T07:41:49.180 回答