支持 IEnumerable 时奇怪的 JSON 序列化

问题描述 投票:0回答:0

我在支持 IEnumerable 和 JSON 序列化时遇到了一个特殊问题。我在这里和网上搜索了一段时间,发现这个问题并不新鲜。但是,当我将它们应用到我的应用程序时,我发现它已经很旧并且不再有效。我在 .NET 7.0 上,这是一个简单的控制台应用程序。另外,我正在 Mac 上执行此操作(这很酷)。

这是我的代码(请注意,IEnumerable 实现在类 JsonNumberRanges 中被注释掉了。另外,请原谅我,我已经有 13 年没有用 C# 编写代码了,所以我只是回到它和我的知识已经很老了):

using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonSerializationProblem
{
    public class NumberRange
    {
        int lowerBound;
        int upperBound;

        public NumberRange()
        {
            lowerBound = 0;
            upperBound = 0;
        }

        public int LowerBound
        {
            get => lowerBound;
            set => lowerBound = value;
        }

        public int UpperBound
        {
            get => upperBound;
            set => upperBound = value;
        }
    }

    public class JsonNumberRanges /*: IEnumerable<NumberRange>*/
    {
        string fileHeader;
        List<NumberRange> numberRanges;

        public JsonNumberRanges()
        {
            fileHeader = "This is a sample Json file.";
        }

        public string FileHeader
        {
            get => fileHeader;
            set => fileHeader = value;
        }

        public List<NumberRange> NumberRanges
        {
            get => numberRanges;
            set => numberRanges = value;
        }

        public NumberRange this[int index]
        {
            get => numberRanges[index];
            set => Add(value);
        }

        internal void Add(NumberRange numberRange)
        {
            if (numberRanges == null)
            {
                numberRanges = new List<NumberRange>();
            }

            numberRanges.Add(numberRange);
        }

        internal int Count
        {
            get
            {
                if (numberRanges == null)
                {
                    return 0;
                }

                return numberRanges.Count;
            }
        }

        /*
        public IEnumerator<NumberRange> GetEnumerator()
        {
            for (int i = 0; i < numberRanges.Count; i++)
            {
                yield return numberRanges[i];
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            // Call the generic version of GetEnumerator().
            return GetEnumerator();
        }
        */
    }
}

这里是主要程序:

using System;
using System.Text.Json;

namespace JsonSerializationProblem
{
    public class Program
    {
        static void Main()
        {
            JsonNumberRanges ranges = new JsonNumberRanges();

            NumberRange range = new NumberRange();
            range.LowerBound = 1;
            range.UpperBound = 20;
            ranges.Add(range);

            range = new NumberRange();
            range.LowerBound = 21;
            range.UpperBound = 40;
            ranges.Add(range);

            range = new NumberRange();
            range.LowerBound = 41;
            range.UpperBound = 60;
            ranges.Add(range);

            range = new NumberRange();
            range.LowerBound = 61;
            range.UpperBound = 80;
            ranges.Add(range);

            range = new NumberRange();
            range.LowerBound = 81;
            range.UpperBound = 100;
            ranges.Add(range);

            string fileName = "TestJsonFile.json";

            var options = new JsonSerializerOptions { WriteIndented = true };
            string jsonString = JsonSerializer.Serialize(ranges, options);
            Console.WriteLine(jsonString);

            // Write the data to the file.
            File.WriteAllText(fileName, jsonString);

            // Now, read back from file.
            jsonString = File.ReadAllText(fileName);

            JsonNumberRanges newRanges = JsonSerializer.Deserialize<JsonNumberRanges>(jsonString);
        }
    }
}

注释掉 IEnumerable 代码后,创建和读回以下文件都没有问题:

{
  "FileHeader": "This is a sample Json file.",
  "NumberRanges": [
    {
      "LowerBound": 1,
      "UpperBound": 20
    },
    {
      "LowerBound": 21,
      "UpperBound": 40
    },
    {
      "LowerBound": 41,
      "UpperBound": 60
    },
    {
      "LowerBound": 61,
      "UpperBound": 80
    },
    {
      "LowerBound": 81,
      "UpperBound": 100
    }
  ]
}

但是,如果我取消注释支持 IEnumerable 的代码,这就是创建的文件(注意缺少 FileHeader 部分):

[
  {
    "LowerBound": 1,
    "UpperBound": 20
  },
  {
    "LowerBound": 21,
    "UpperBound": 40
  },
  {
    "LowerBound": 41,
    "UpperBound": 60
  },
  {
    "LowerBound": 61,
    "UpperBound": 80
  },
  {
    "LowerBound": 81,
    "UpperBound": 100
  }
]

所以当我的代码试图读回文件时,它崩溃并出现以下调用堆栈:

Unhandled exception. System.NotSupportedException: The collection type 'JsonSerializationProblem.JsonNumberRanges' is abstract, an interface, or is read only, and could not be instantiated and populated. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
 ---> System.NotSupportedException: The collection type 'JsonSerializationProblem.JsonNumberRanges' is abstract, an interface, or is read only, and could not be instantiated and populated.
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException(ReadStack& state, Utf8JsonReader& reader, NotSupportedException ex)
   at System.Text.Json.Serialization.Converters.IEnumerableOfTConverter`2.CreateCollection(Utf8JsonReader& reader, ReadStack& state, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at JsonSerializationProblem.Program.Main() in <PATH REMOVED>/JsonSerializationProblem/Program.cs:line 56
[createdump] Gathering state for process 33717 
[createdump] Crashing thread 8af20 signal 6 (0006)
[createdump] Writing crash report to file /var/folders/2r/cm4pgxks7xvd840fcbv30rqh0000gn/T/coredump.33717.crashreport.json
[createdump] Crash report successfully written
[createdump] Writing minidump with heap to file /var/folders/2r/cm4pgxks7xvd840fcbv30rqh0000gn/T/coredump.33717
[createdump] Written 493744296 bytes (120543 pages) to core file
[createdump] Target process is alive
[createdump] Dump successfully written in 2832ms
bash: line 1: 33717 Abort trap: 6           "/usr/local/share/dotnet/dotnet" "<PATH REMOVED>/JsonSerializationProblem/bin/Debug/net7.0/JsonSerializationProblem.dll"

就像我上面提到的,我在 Stack Overflow 和网上阅读了很多话题,并尝试了一些推荐的解决方案。例如,我尝试应用无效的 [JsonObject](一个线程建议这样做)。我查看了 JsonObjectAttribute 类,因为有几个线程指向它。我还在 Reddit 上发现了一个帖子,其中有人在抱怨微软对 JSON 支持的实现,但没有帮助。到目前为止,我尝试过的一切都没有奏效。

有没有人遇到过这个,你能解决吗?如果是这样,你是怎么做到的?

c# json .net serialization ienumerable
© www.soinside.com 2019 - 2024. All rights reserved.