为自引用 class 实例反序列化 json 时出现 StackOverflowException
StackOverflowException when deserializing json for self referencing class instances
我有一个 class 包含 Range[]
作为 属性 和 Range
class 是一个自引用 class。我使用 [JsonIgnore]
来防止 WhosebugException
但它仅适用于 Serialize
而不是 Deserialize
。我该如何解决这个问题?
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace testoverflow
{
class Program
{
public static void Main(string[] args)
{
GlobalVariable.Json = "[{\"TotalBytesReceived\":0,\"Id\":\"b03750fb291a46708f8e1a7409553075\",\"NofThread\":8,\"Speed\":0,\"Progress\":0.0,\"FilePath\":\"C:\\Users\\kafeinaltor\\Downloads\",\"RangeDir\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\",\"Url\":\"http://ipv4.download.thinkbroadband.com/20MB.zip\",\"Ranges\":[{\"Start\":0,\"End\":9223372036854775806,\"TotalBytesReceived\":0,\"IsDownloaded\":false,\"FileId\":\"87cd7715dc0740c1b82ddd681bf2523d\",\"Size\":9223372036854775807,\"Status\":4,\"IsIdle\":false,\"SaveDir\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\",\"FilePath\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\\87cd7715dc0740c1b82ddd681bf2523d\",\"Md5Checksum\":null}],\"Info\":null,\"DownloadRequestMessage\":null}]";
var a = new MTDO();
Console.WriteLine(GlobalVariable.Json);
Console.ReadKey(true);
}
public static class GlobalVariable
{
public static string Json { get; set; }
}
public class MTDO
{
public MTDO()
{
Ranges = new Range[]
{
new Range(0L, 100L, ""),
new Range(101L, 200L, "")
};
Id = Guid.NewGuid().ToString("N");
Reminder.AddOrUpdate(this);
}
public string Id { get; set; }
public Range[] Ranges{ get; set; }
}
public class Range
{
public long Start { get; set; }
public long End { get; set; }
public string SaveDir { get; set; }
public long TotalBytesReceived{ get; set; }
public Range(long start, long end, string saveDir)
{
this.Start = start;
this.End = end;
this.SaveDir = Guid.NewGuid().ToString();
}
[JsonIgnore]
public Range Remaining
{
get
{
return new Range(Start + TotalBytesReceived, End, SaveDir);
}
}
}
public class Reminder
{
public Reminder()
{
}
public static void AddOrUpdate(MTDO mtdo)
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
var exists = list.Any(x => x.Id == mtdo.Id);
if (!exists)
list.Add(mtdo);
else
{
var i = list.Select((x, j) => new {val = x, index = j})
.First(x => x.val.Id == mtdo.Id).index;
list[i] = mtdo;
}
WriteJson(list);
}
public static List<MTDO> ReadList()
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
return list;
}
static string Read()
{
try
{
return GlobalVariable.Json;
}
catch
{
return "";
}
}
static void WriteJson(List<MTDO> list)
{
GlobalVariable.Json = JsonConvert.SerializeObject(list);
}
}
}
}
更新:我更新了我的问题,在控制台应用程序中添加了最少的可重现代码。可以直接copy/paste和运行。
问题是你有一个无限递归:
- 您调用 MTDO 构造函数
- 在 MTDO 构造函数中调用
Reminder.AddOrUpdate(this);
- 在那个方法里面你有
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
- 再次调用 MTDO 构造函数(第 1 步)
不断重复这些步骤,直到您遇到 WhosebugException。
我有一个 class 包含 Range[]
作为 属性 和 Range
class 是一个自引用 class。我使用 [JsonIgnore]
来防止 WhosebugException
但它仅适用于 Serialize
而不是 Deserialize
。我该如何解决这个问题?
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace testoverflow
{
class Program
{
public static void Main(string[] args)
{
GlobalVariable.Json = "[{\"TotalBytesReceived\":0,\"Id\":\"b03750fb291a46708f8e1a7409553075\",\"NofThread\":8,\"Speed\":0,\"Progress\":0.0,\"FilePath\":\"C:\\Users\\kafeinaltor\\Downloads\",\"RangeDir\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\",\"Url\":\"http://ipv4.download.thinkbroadband.com/20MB.zip\",\"Ranges\":[{\"Start\":0,\"End\":9223372036854775806,\"TotalBytesReceived\":0,\"IsDownloaded\":false,\"FileId\":\"87cd7715dc0740c1b82ddd681bf2523d\",\"Size\":9223372036854775807,\"Status\":4,\"IsIdle\":false,\"SaveDir\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\",\"FilePath\":\"C:\\Users\\kafeinaltor\\AppData\\Roaming\\87cd7715dc0740c1b82ddd681bf2523d\",\"Md5Checksum\":null}],\"Info\":null,\"DownloadRequestMessage\":null}]";
var a = new MTDO();
Console.WriteLine(GlobalVariable.Json);
Console.ReadKey(true);
}
public static class GlobalVariable
{
public static string Json { get; set; }
}
public class MTDO
{
public MTDO()
{
Ranges = new Range[]
{
new Range(0L, 100L, ""),
new Range(101L, 200L, "")
};
Id = Guid.NewGuid().ToString("N");
Reminder.AddOrUpdate(this);
}
public string Id { get; set; }
public Range[] Ranges{ get; set; }
}
public class Range
{
public long Start { get; set; }
public long End { get; set; }
public string SaveDir { get; set; }
public long TotalBytesReceived{ get; set; }
public Range(long start, long end, string saveDir)
{
this.Start = start;
this.End = end;
this.SaveDir = Guid.NewGuid().ToString();
}
[JsonIgnore]
public Range Remaining
{
get
{
return new Range(Start + TotalBytesReceived, End, SaveDir);
}
}
}
public class Reminder
{
public Reminder()
{
}
public static void AddOrUpdate(MTDO mtdo)
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
var exists = list.Any(x => x.Id == mtdo.Id);
if (!exists)
list.Add(mtdo);
else
{
var i = list.Select((x, j) => new {val = x, index = j})
.First(x => x.val.Id == mtdo.Id).index;
list[i] = mtdo;
}
WriteJson(list);
}
public static List<MTDO> ReadList()
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
return list;
}
static string Read()
{
try
{
return GlobalVariable.Json;
}
catch
{
return "";
}
}
static void WriteJson(List<MTDO> list)
{
GlobalVariable.Json = JsonConvert.SerializeObject(list);
}
}
}
}
更新:我更新了我的问题,在控制台应用程序中添加了最少的可重现代码。可以直接copy/paste和运行。
问题是你有一个无限递归:
- 您调用 MTDO 构造函数
- 在 MTDO 构造函数中调用
Reminder.AddOrUpdate(this);
- 在那个方法里面你有
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
- 再次调用 MTDO 构造函数(第 1 步)
不断重复这些步骤,直到您遇到 WhosebugException。