![](/img/trans.png)
[英]serializing a Dictionary<string,object> in ProtoBuf-net fails
[英]Serializing List<Dictionary<string,object>> with Protobuf-Net
我有一個要序列化的字典列表,但是出現以下錯誤:
不支持System.NotSupportedExceptionNested或鋸齒狀的列表和數組
甚至可以序列化嗎? 我嘗試將其推送到其他類,並使用List<Dto>
,其中Dto
類是Dictionary
的IEnumerable
, Dictionary
中的對象具有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。 我不會在這里詳細說明為什么需要它,足以說明您需要使用2個代理類的組合,並且需要使用BinaryFormatter將對象Type序列化為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屬性(typeof對象)。 它將引發異常:“未為類型定義任何序列化器:System.Object”
為了解決這個問題,我們需要提供Protobuf-net可以序列化的MyNameValueInfo的代理。 首先注冊代理類型(只需完成一次):
RuntimeTypeModel.Default.Add(typeof(MyNameValueInfo),false).SetSurrogate(typeof(MyNameValueInfoSurrogate));;
然后實現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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.