我在支持 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 支持的实现,但没有帮助。到目前为止,我尝试过的一切都没有奏效。
有没有人遇到过这个,你能解决吗?如果是这样,你是怎么做到的?