对象(通用)的 Protobuf-net 序列化抛出错误没有为类型定义序列化程序:System.Object
Posted
技术标签:
【中文标题】对象(通用)的 Protobuf-net 序列化抛出错误没有为类型定义序列化程序:System.Object【英文标题】:Protobuf-net serialization of object (generic) throws error No serializer defined for type: System.Object 【发布时间】:2020-11-24 00:56:48 【问题描述】:如何使用 Protobuf-net 序列化一个 generic(T) 对象,该对象可以保存任何类型的数据(int / string / DateTime)。以下是我的代码
[ProtoContract]
public class E1DataRow
[ProtoMember(1)]
public List<NameValue> NameValues get; set;
public E1DataRow()
NameValues = new List<NameValue>();
public void AddNameValue(string name, object obj, Type type)
NameValues.Add(new NameValue Name = name, Value = obj, ValueType = type );
[ProtoContract]
public class NameValue
[ProtoMember(1)]
public string Name get; set;
[ProtoMember(2)]
public object Value get; set;
[ProtoMember(3)]
public Type ValueType get; set;
序列化代码
var e1DataRows = new List<E1DataRow>();
/*
Code to add Data rows to e1DataRows
e1DataRow.AddNameValue(column.ColumnName, value, column.TypeOfColumn);
*/
using (var stream = File.OpenWrite(path))
Serializer.Serialize(stream, e1DataRows);
[ProtoMember(2, DynamicType = true)]
public object Value get; set;
以上代码抛出以下错误(DynamicType = true) ProtoMemberAttribute.DynamicType' 已过时:'此版本中当前未实现引用跟踪和动态类型;他们可能会在以后恢复;这部分是由于对这些功能是否可行的怀疑,部分是由于对测试所有场景的信心(这需要时间;那个时间还没有发生);邀请反馈'
如果您能帮助了解如何使用 Protobug-net 序列化列表,那就太好了。谢谢...
【问题讨论】:
看起来 Protobuf-net 可以很好地处理泛型类型。尝试将public class NameValue
转换为public class NameValue<T>
或改用现有的KeyValuePair<TKey,TValue>
。
@schnitz77 感谢您的 cmets。公共类NameValue<T>
的问题是我不能拥有不同类型的List<NameValue>
(我猜)。 KeyValuePair<TKey, TValue>
是个好主意,但每次我添加新密钥时都会花费我进行散列操作。基本上,我正在尝试将数据集(SqlReader)转换为简单的 POCO 类进行序列化。
【参考方案1】:
您可能想查看 https://github.com/dotarj/protobuf-net-data - 这与 protobuf-net 无关(不同的作者等),但它使用 protobuf-net 来执行 DataTable
和数据的序列化-读者,所以它可能做你想要的现成的。
至于自己实现:
protobuf-net 根本不支持object
(或dynamic
,这只是object
的一种奇特的拼写方式)。有一些方法可以解决这个问题,基本上类似于 protobuf 中的 oneof
处理 - 即类似于(在 protobuf 术语中):
message Foo
oneof payload
string payload_string = 1;
bool payload_bool = 2;
int32 payload_int32 = 3;
float payload_float = 4;
// etc
由于“条件序列化”,这很容易在 protobuf-net 中组合在一起,这意味着您可以执行以下操作:
public object Value get; set;
[ProtoMember(1)]
public string ValueString
get => (string)Value;
set => Value = value;
public bool ShouldSerializeValueString()
=> Value is string;
[ProtoMember(2)]
public string ValueBoolean
get => (bool)Value;
set => Value = value;
public bool ShouldSerializeValueBoolean()
=> Value is string;
// etc
【讨论】:
感谢 Marc 在 protobuf-net 上所做的工作。我在使用 protobuf-net-data 时遇到了严重错误,只是意识到它可以与 protobuf-net 包的 2.3.2 版本一起使用。我了解 protobuf-net-data 的作者是不同的,但您是否知道是否有任何工作可以使其与您的最新版本的 protobuf-net一起使用> 包。无论如何,再次感谢您的出色工作。【参考方案2】:如果在 c# >= 4 上,您可能需要尝试以下操作:
[ProtoContract]
public class E1DataRow
[ProtoMember(1)]
public List<NameValue<dynamic>> NameValues get; set;
public E1DataRow()
NameValues = new List<NameValue<dynamic>>();
public void AddNameValue(string name, dynamic obj)
NameValues.Add(new NameValue<dynamic> Name = name, Value = obj );
public class NameValue<T>
[ProtoMember(1)]
public string Name get; set;
[ProtoMember(2)]
public T Value get; set;
[ProtoMember(3)]
public Type ValueType get return Value.GetType();
不确定 Protobuf-net 是否喜欢 List<NameValue<dynamic>>
,目前无法对其进行测试。
ProtoMember(3)
ValueType
可能没有必要,因为无论如何都是只读的。
【讨论】:
以上是关于对象(通用)的 Protobuf-net 序列化抛出错误没有为类型定义序列化程序:System.Object的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能使用 ProtoBuf-Net 正确反序列化我的对象?