4

在以下示例中:

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 实现,但正如您所期望的那样。

4

4 回答 4

6

重新 protobuf-net,我维护:

这里的问题不是值类型(它通常可以很好地处理) - 它是开放object使用,这意味着它根本不知道期望什么数据,因此不知道如何编码/解码它。

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

也许如果你能澄清用例,我可能会提供更多帮助?例如,上面的内容不能很好地使用DataContractSerializer或者XmlSerializer......

重新 dotnet-protobufs; 我无法真正发表评论,但我敢肯定它会更不宽容;它旨在与从 .proto 文件生成的类一起使用,因此object永远不会进入模型(乔恩:如果我错了,请纠正我)。

如果你留下更多信息,你能在这里发表评论吗?所以我可以很容易地找到它......或者,直接给我发邮件(请参阅我的 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
}
于 2009-02-18T21:04:28.690 回答
3

(更新)

对; 想通了...上面示例中的主要问题是价值获取者;他们正在抛出异常。还有一些图书馆故障(现已修复)。

但是,最简单的方法是Nullable<T>传递属性:

    [ProtoMember(1)]
    private int? ValueInt32
    {
        get { return Get<int>(); }
        set { Value = value; }
    }

等,与:

    private T? Get<T>() where T : struct
    {
        return (Value != null && Value is T) ? (T?)Value : (T?)null;
    }

这和 *Specified 方法都已经过测试,现在可以正常工作。

于 2009-02-19T05:41:33.440 回答
0

这就像我的想法一样。让我知道你的想法。自然,我必须为我需要支持的每种值类型添加一个子类。你怎么看?有没有更好的方法,您是否发现这种方法效率低下?

[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)
    { }
}
于 2009-02-18T23:29:25.457 回答
0

直接封装似乎可以正常工作,而所有属性都没有额外的开销,方式如下:

[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
}
于 2009-02-19T01:35:05.653 回答