带有字符串的代码示例也会引发异常:
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 RoutineData.txt", json);`
由于自我引用错误,我无法使用 Json.net 序列化List<LinkedListNode<object>>
。
错误:检测到类型为"System.Collections.Generic.LinkedListNode'1[Calendar_Module.ScheduleEvent]"的属性"Previous"的自引用循环。路径 '[0]。用户数据.日历.天.2017-04-02T00:00:00[0].下一个.下一个.下一个.下一个.下一个"。
请帮忙
序列化List<LinkedListNode<string>>
有点奇怪 - 通常只会序列化底层链表。 也许您正在尝试序列化一个表,该表以与基础列表不同的顺序提供节点?
如果是这种情况,似乎可以使用PreserveReferencesHandling.All
与ReferenceLoopHandling.Serialize
结合使用来序列化节点列表,但是由于 Json.NET 的一些限制,这失败了:
-
PreserveReferencesHandling
不是为只读属性实现的(见这里),但LinkedListNode.List
、.Next
和.Previous
都是只读的。 这会阻止循环依赖项的正确序列化,并最终导致下一个和上一个节点属性上的无限递归。 -
PreserveReferencesHandling
不会为具有非默认构造函数的对象实现(请参阅此处),但LinkedListNode<T>
的唯一公共构造函数已参数化。
因此,您需要为节点列表创建自定义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>
的成员。 如果不是,将引发异常。
样品小提琴。
Unhandled Exception:
System.Runtime.Serialization.SerializationException: Type System.Collections.Generic.LinkedListNode`1[System.String] is not marked as Serializable.
换句话说,如果你打算序列化它,不要使用LinkedListNode。