为自引用类实例反序列化json时出现StackOverflowException

问题描述

我有一个包含Range[]作为属性的类,而Range类是一个自引用类。我使用[JsonIgnore]来防止StackoverflowException,但是它仅对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);
            }
        }
    }
}

更新:我已经更新了myquestion,在控制台应用程序中添加了最少的可复制代码。您可以复制/粘贴并直接运行。

解决方法

问题在于您具有无限递归:

  1. 您致电MTDO构造函数
  2. 在MTDO内部构造函数中,您调用Reminder.AddOrUpdate(this);
  3. 在该方法中,您有var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
  4. 再次调用MTDO构造函数(步骤1)

这些步骤不断重复,直到您得到StackOverflowException。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...