.net C#中的协议缓冲区:如何处理装箱值类型

.net C#中的协议缓冲区:如何处理装箱值类型,.net,protocol-buffers,protobuf-net,.net,Protocol Buffers,Protobuf Net,在以下示例中: public class RowData { public object[] Values; } public class FieldData { public object Value; } 我很好奇protobuf-net或dotnet-protobufs如何处理这样的类。我更熟悉protobuf net,所以我实际拥有的是: [ProtoContract] public class RowData { [ProtoMember(1)] p

在以下示例中:

public class RowData
{
    public object[] Values;
}

public class FieldData
{
    public object Value;
}
我很好奇protobuf-net或dotnet-protobufs如何处理这样的类。我更熟悉protobuf net,所以我实际拥有的是:

[ProtoContract]
public class RowData
{
    [ProtoMember(1)]
    public object[] Values;
}
[ProtoContract]
public class FieldData
{
    [ProtoMember(1)]
    public object Value;
}
但是我得到一个错误,说“找不到合适的默认对象编码”。有没有一个简单的方法来对待这些课程,我只是不知道

要详细说明用例,请执行以下操作:

这是远程处理中使用的数据类的缩小版本。所以本质上看起来是这样的:

FieldData data = new FieldData();
data.Value = 8;

remoteObject.DoSomething(data);

注意:为了简单起见,我省略了ISerializable实现,但正如您所期望的那样。

Re protobuf-net,我维护:

这里的问题不是值类型(它通常可以很好地处理),而是open
对象的用法,这意味着它根本不知道需要什么数据,因此也不知道如何对其进行编码/解码

目前,我想不出一个简单/干净的方法来处理这个问题。它将处理一系列常见的值类型场景、列表和基于契约(数据契约、原型契约或一些xml模式)的任何层次结构,但它需要一个线索

如果你能澄清这个用例,我也许能提供更多帮助?例如,上述方法在
DataContractSerializer
XmlSerializer
中都不起作用

Re dotnet协议;我真的无法评论,但我很确定这会更不宽容;它用于从.proto文件生成的类,因此
对象
永远不会进入模型(Jon:如果我错了,请纠正我)

如果你留下更多的信息,你能在这里发表评论吗?所以我可以很容易地找到它。。。或者,直接给我发封邮件(参见我的SO档案)


编辑-这是我脑子里想的一件骇人的事情-它目前不起作用,但我明天(可能)会弄清楚原因。请注意,从理论上讲,额外的成员可能都是私有的-我只是想在调试时让它变得简单。请注意,这不会占用任何额外的存储空间。就像我说的,它今天不起作用,但它应该-我会找出原因

[ProtoContract]
public class FieldData
{
    public object Value {get;set;}

    [ProtoMember(1)]
    public int ValueInt32 {
        get { return (int)Value; } set { Value = value; } }
    public bool ValueInt32Specified {
        get { return Value != null && Value is int; } set { } }

    [ProtoMember(2)]
    public float ValueSingle {
        get { return (float)Value; } set { Value = value; } }
    public bool ValueSingleSpecified {
        get { return Value != null && Value is float; } set { } }

    // etc for expected types
}

这和我的想法差不多。让我知道你的想法。当然,我必须为我需要支持的每个值类型添加一个子类。你怎么认为?有没有更好的方法,你觉得这种方法效率低吗

[ProtoContract, Serializable]
[ProtoInclude(1, typeof(Int32FieldData))]
public abstract class FieldDataBase : ISerializable
{
    [ProtoIgnore]
    public abstract object Value { get; set;}
    protected FieldDataBase()
    { }

    #region ISerializable Members
    protected FieldDataBase(SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge<FieldDataBase>(info, this);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize<FieldDataBase>(info, this);
    }

    #endregion
}

[ProtoContract, Serializable]
public class Int32FieldData : FieldDataBase
{
    [ProtoMember(1)]
    public int? Int32Value;

    [ProtoIgnore]
    public override object Value
    {
        get { return this.Int32Value.HasValue ? this.Int32Value : null; }
        set { this.Int32Value = (int?)value; }
    }
    public Int32FieldData() { }
    protected Int32FieldData(SerializationInfo info, StreamingContext context)
        :base(info, context)
    { }
}
[协议,可序列化]
[协议包括(1,类型(Int32FieldData))]
公共抽象类字段数据库:ISerializable
{
[忽略]
公共抽象对象值{get;set;}
受保护的字段数据库()
{ }
#区域ISerializable成员
受保护的FieldDataBase(SerializationInfo信息、StreamingContext上下文)
{
Serializer.Merge(info,this);
}
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
{
序列化器。序列化(信息,此);
}
#端区
}
[协议,可序列化]
公共类Int32FieldData:FieldDataBase
{
[原成员(1)]
公共int?Int32Value;
[忽略]
公共覆盖对象值
{
获取{返回this.Int32Value.HasValue?this.Int32Value:null;}
设置{this.Int32Value=(int?)value;}
}
公共Int32FieldData(){}
受保护的Int32FieldData(SerializationInfo信息、StreamingContext上下文)
:base(信息、上下文)
{ }
}

通过以下方式,直接封装似乎可以正常工作,而不会增加所有属性的额外开销:

[ProtoContract, Serializable]
public class ObjectWrapper : ISerializable
{
    public ObjectWrapper()
    { }
    [ProtoIgnore]
    public object Value
    {
        get
        {
            if (Int32Value.HasValue)
                return Int32Value.Value;
            else if (BinaryValue != null)
                return BinaryValue;
            else
                return StringValue;
        }
        set
        {
            if (value is int)
                this.Int32Value = (int)value;
            else if (value is byte[])
                this.BinaryValue = (byte[])value;
            else if (value is string)
                this.StringValue = (string)value;
        }
    }
    [ProtoMember(1)]
    private int? Int32Value;
    [ProtoMember(2)]
    private string StringValue;
    [ProtoMember(3)]
    private byte[] BinaryValue;
            // etc

    #region ISerializable Members
    protected ObjectWrapper(SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge<ObjectWrapper>(info, this);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize<ObjectWrapper>(info, this);
    }

    #endregion
}
[协议,可序列化]
公共类ObjectWrapper:ISerializable
{
公共对象包装器()
{ }
[忽略]
公共对象价值
{
得到
{
if(Int32Value.HasValue)
返回Int32Value.Value;
else if(二进制值!=null)
返回二进制值;
其他的
返回字符串值;
}
设置
{
if(值为int)
this.Int32Value=(int)值;
else if(值为字节[])
this.BinaryValue=(字节[])值;
else if(值为字符串)
this.StringValue=(字符串)值;
}
}
[原成员(1)]
私有int?Int32Value;
[原成员(2)]
私有字符串字符串值;
[原成员(3)]
私有字节[]二进制值;
//等
#区域ISerializable成员
受保护的ObjectWrapper(SerializationInfo信息、StreamingContext上下文)
{
Serializer.Merge(info,this);
}
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
{
序列化器。序列化(信息,此);
}
#端区
}
(更新)

对,;我想出来了。。。我上面示例中的主要问题是值获取程序;他们在抛出例外。还有一些库故障()

但是,最简单的方法是
可为空
传递属性:

    [ProtoMember(1)]
    private int? ValueInt32
    {
        get { return Get<int>(); }
        set { Value = value; }
    }
[原成员(1)]
私人整数?值32
{
获取{return get();}
设置{Value=Value;}
}
等等,包括:

    private T? Get<T>() where T : struct
    {
        return (Value != null && Value is T) ? (T?)Value : (T?)null;
    }
private T?Get()其中T:struct
{
返回值(Value!=null&&Value为T)?(T?)值:(T?)null;
}

这一方法和*指定的方法都是有效的,现在可以正常工作。

我不能对DataContractSerializer发表评论,但XmlSerializer对此没有问题。我考虑的更多是继承。我会发布我的想法。@PatrickSzalapski你有一个不满意的特定场景吗?只是想知道“你心中的黑客行为”是否可以或应该起作用。@Patrick动态类型支持提供了一些这方面的支持,但它并不适合每种场景OK-有一种方法可以做到;这很有意思,但应该有用。。。正在更新…嗯,看起来可能有空值的问题?以哪种方式“问题”?不幸的是,wire格式没有空值的概念,因此cl