序列化列表<;词典<;字符串,对象>>;使用Protobuf Net
本文关键字:gt lt Net 使用 Protobuf 对象 字符串 列表 词典 序列化 | 更新日期: 2023-09-27 18:20:47
我有一个想要序列化的字典列表,但我得到了以下错误:
System.NotSupportedException不支持嵌套或锯齿状列表和数组
这有可能连载吗?我试着把它推到另一个类中,并得到了一个List<Dto>
,其中Dto
类是Dictionary
的IEnumerable
,字典中的对象是DynamicType
,但它仍然不起作用。我是完全错了,还是错过了一些微妙的东西?
示例代码:
var zone = DateTimeZoneProviders.Tzdb["Europe/London"];
_testObj = new Person
{
Name = "Homer",
Age = 38,
Timestamp = new ZonedDateTime(Instant.FromUtc(2013, 6, 12, 17, 53, 23), zone),
Target = new DataCollection(new Dictionary<string, Type>()
{
{"Date", typeof(DateTime)}
}, new List<Dictionary<string, object>>
{
new Dictionary<string, object>
{
{"Date", new DateTime(2015, 1, 1)}
}
}
, new List<string> { "Date" })
和DataCollection
:
[Serializable, ProtoContract(IgnoreListHandling = true), DataContract, JsonObject]
public class DataCollection : IEnumerable<IDictionary<string, object>>
{
public DataCollection(Dictionary<string, Type> fields, List<Dictionary<string, object>> data, List<string> keyFields)
{
Fields = fields;
KeyFields = keyFields;
Data = data;
}
public DataCollection()
{
Fields = new Dictionary<string, Type>();
Data = new List<Dictionary<string, object>>();
KeyFields = new List<string>();
}
[ProtoMember(1), DataMember]
public Dictionary<string, Type> Fields { get; set; }
[ProtoMember(2), DataMember]
public List<string> KeyFields { get; set; }
[ProtoMember(3), DataMember]
public List<Dictionary<string, object>> Data { get; set; }
public void Add(Dictionary<string, object> value)
{
Data.Add(value);
}
public IEnumerator<IDictionary<string, object>> GetEnumerator()
{
return Data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
如果我没有ProtoMember(3),我可以连载。
因此问题归结为Protobuf net,不喜欢Dictionary中的对象Type,这是正确的。我不会详细说明为什么我需要它,只需说你需要使用两个代理类的组合,对象类型需要用BinaryFormatter串行化为byte[],然后发送到Protobuf-net,因为Protobuf规范不会确认对象类型。
我从这个网站复制解决方案的灵感:http://rushfrisby.com/serializing-non-serializable-types-with-protobuf/
根据张贴解决方案的规则,而不是链接到外部网站单独:
以此类为例:
[DataContract]
public class MyNameValueInfo
{
[DataMember(Order = 1)]
public string Name { get; set; }
[DataMember(Order = 2)]
public object Value { get; set; }
}
MyNameValueInfo无法序列化,因为它不知道如何序列化Value属性(对象类型)。它将抛出一个异常:"没有为类型定义序列化程序:System.Object"
为了解决这个问题,我们需要为MyNameValueInfo提供一个代理,protobuf-net可以对其进行序列化。首先注册代理类型(只需要执行一次):
RuntimeTypeModel.Default.Add(typeof(MyNameValueInfo),false).Surrogate(typeof(MyName ValueInfoSurrogate));
然后实现MyNameValueInfoSurrogate,这样它就可以从/转换为MyNameValueInfo,并且可以通过protobuf-net:进行序列化
[DataContract]
public class MyNameValueInfoSurrogate
{
//string is serializable so we'll just copy this property back and forth
[DataMember(Order = 1)]
public string Name { get; set; }
//byte[] is serializable so we'll need to convert object to byte[] and back again
[DataMember(Order = 2)]
public byte[] Value { get; set; }
public static implicit operator MyNameValueInfo(MyNameValueInfoSuggorage suggorage)
{
return suggorage == null ? null : new MyNameValueInfo
{
Name = suggorage.Name,
Value = Deserialize(suggorage.Value)
};
}
public static implicit operator MyNameValueInfoSuggorage(MyNameValueInfo source)
{
return source == null ? null : new MyNameValueInfoSuggorage
{
Name = source.Name,
Value = Serialize(source.Value)
};
}
private static byte[] Serialize(object o)
{
if (o == null)
return null;
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, o);
return ms.ToArray();
}
}
private static object Deserialize(byte[] b)
{
if (b == null)
return null;
using (var ms = new MemoryStream(b))
{
var formatter = new BinaryFormatter();
return formatter.Deserialize(ms);
}
}
}