2017-04-08 81 views
-6

與串的代碼示例也拋出異常:序列化列表<一個LinkedListNode <object>>使用Json.net

LinkedList<string> l = new LinkedList<string>(); 
     l.AddLast("Kuku"); 
     l.AddLast("Riku"); 
     l.AddLast("Ok"); 
     List<LinkedListNode<string>> lst = new List<LinkedListNode<string>>(); 
     lst.Add(l.First); 
     lst.Add(l.First.Next); 
     lst.Add(l.Last); 

     string json = JsonConvert.SerializeObject(lst, Formatting.Indented, 
     new JsonSerializerSettings 
     { 
      ReferenceLoopHandling = ReferenceLoopHandling.Serialize 
     }); 
     File.WriteAllText(@"C:\Student Routine\Data.txt", json);` 

我不能序列​​由於自我引薦誤差,使用Json.net。

錯誤:爲屬性'Previous'檢測到自回參考循環,類型爲'System.Collections.Generic.LinkedListNode`1 [Calendar_Module.ScheduleEvent]'。路徑'[0] .UserData.Calendar.Days.2017-04-02T00:00:00 [0] .Next.Next.Next.Next.Next.Next'。

請幫助

+1

你究竟想在這裏完成什麼? –

回答

2

序列化List<LinkedListNode<string>>是有點的一個奇怪的事情要做 - 通常一個只想序列化底層鏈表。也許你試圖序列化一個表,該表給出了與底層列表不同的順序?

如果是這樣的話,它可能會出現,人們可以使用序列化與PreserveReferencesHandling.All聯合ReferenceLoopHandling.Serialize節點列表,但是這個失敗,因爲Json.NET的一些限制:

  • PreserveReferencesHandling不讀執行 - 僅屬性(請參閱here),但LinkedListNode.List,.Next.Previous均爲只讀屬性。這會阻止循環依賴的正確序列化,並最終導致對下一個和前一個節點屬性的無限遞歸。

  • PreserveReferencesHandling未針對具有非默認構造函數的對象實現(請參見here),但LinkedListNode<T>的唯一公共構造方法已參數化。

因此,您需要爲您的節點列表中custom JsonConverter

public class LinkedListNodeListConverter<T> : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return typeof(List<LinkedListNode<T>>).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var list = (existingValue as IList<LinkedListNode<T>> ?? (IList<LinkedListNode<T>>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator()); 
     var table = serializer.Deserialize<LinkedListNodeOrderTable<T>>(reader); 
     foreach (var node in table.ToNodeList()) 
      list.Add(node); 
     return list; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var list = (IList<LinkedListNode<T>>)value; 
     var table = LinkedListNodeOrderTable<T>.FromList(list); 
     serializer.Serialize(writer, table); 
    } 
} 

class LinkedListNodeOrderTable<T> 
{ 
    public static LinkedListNodeOrderTable<T> FromList(IList<LinkedListNode<T>> nodeList) 
    { 
     if (nodeList == null) 
      return null; 
     try 
     { 
      var list = nodeList.Where(n => n != null).Select(n => n.List).Distinct().SingleOrDefault(); 
      var table = new LinkedListNodeOrderTable<T>(list); 
      var dictionary = list == null ? null : list.EnumerateNodes().Select((n, i) => new KeyValuePair<LinkedListNode<T>, int>(n, i)).ToDictionary(p => p.Key, p => p.Value); 
      table.Indices = nodeList.Select(n => (n == null ? -1 : dictionary[n])).ToList(); 
      return table; 
     } 
     catch (Exception ex) 
     { 
      throw new JsonSerializationException(string.Format("Failed to construct LinkedListNodeOrderTable<{0}>", typeof(T)), ex); 
     } 
    } 

    public LinkedListNodeOrderTable(LinkedList<T> List) 
    { 
     this.List = List; 
    } 

    public LinkedList<T> List { get; set; } 

    public List<int> Indices { get; set; } 

    public IEnumerable<LinkedListNode<T>> ToNodeList() 
    { 
     if (Indices == null || Indices.Count < 1) 
      return Enumerable.Empty<LinkedListNode<T>>(); 
     var array = List == null ? null : List.EnumerateNodes().ToArray(); 
     return Indices.Select(i => (i == -1 ? null : array[i])); 
    } 
} 

public static class LinkedListExtensions 
{ 
    public static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>(this LinkedList<T> list) 
    { 
     if (list == null) 
      yield break; 
     for (var node = list.First; node != null; node = node.Next) 
      yield return node; 
    } 
} 

,並使用以下設置:

var settings = new JsonSerializerSettings 
{ 
    Converters = { new LinkedListNodeListConverter<string>() }, 
}; 
string json = JsonConvert.SerializeObject(lst, Formatting.Indented, settings); 

產生的JSON的樣子:

{ 
    "List": [ 
    "Kuku", 
    "Riku", 
    "Ok" 
    ], 
    "Indices": [ 
    0, 
    1, 
    2 
    ] 
} 

請注意,轉換器假定列表中的所有節點都是相同底層LinkedList<T>的成員。如果不會拋出異常。

樣品fiddle

+0

非常感謝你,非常有幫助 –

0
Unhandled Exception: 
System.Runtime.Serialization.SerializationException: Type System.Collections.Generic.LinkedListNode`1[System.String] is not marked as Serializable. 

換句話說,如果你打算把它序列化不使用一個LinkedListNode ...

+0

這是可能的,但是引用存在問題。如果你使用BinarryFormatter,你需要Serializable屬性 –