在以下示例中:
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实现,但它正如您所期望的那样。
答案 0 :(得分:6)
Re protobuf-net,我保持:
这里的问题不是值类型(它通常可以正常处理) - 它是开放的object
用法,这意味着它根本不知道期望什么数据,因此它如何编码/解码它。
目前,我想不出一个简单/干净的方法来处理这个问题。它将处理一系列常见的值类型场景,列表以及基于契约(数据契约,原始契约或某些xml-schemas)的任何层次结构,但它需要线索
也许如果你能澄清一下用例,我或许可以提供更多帮助?例如,上述内容与DataContractSerializer
或XmlSerializer
无关......
Re dotnet-protobufs;我无法评论,但我很确定它会更加宽容;它旨在与.proto文件生成的类一起使用,因此object
将永远不会进入模型(Jon:如果我错了,请纠正我)。
如果您确实留下了更多信息,请在此发表评论吗?所以我可以很容易地找到它......或者,直接给我发邮件(参见我的SO资料)。
编辑 - 这是我想到的hacky事情 - 它现在不起作用,但我会明白为什么明天(可能)。请注意,理论上额外的成员都可以是私有的 - 我只是想在调试时轻松实现。请注意,这不需要任何额外的存储空间。就像我说的,它今天不起作用,但应该 - 我会找出原因......
[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
}
答案 1 :(得分:3)
(更新)
右;想通了......上面我的样本中的主要问题是价值吸引者;他们抛出异常。还有一些库故障(now fixed)。
但是,最简单的方法是Nullable<T>
pass-thru属性:
[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;
}
这个和*指定的方法都是tested,现在工作正常。
答案 2 :(得分: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)
{ }
}
答案 3 :(得分: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
}