System.Text.Json 中支持的集合类型
本文概述了可进行序列化和反序列化的集合的概述。 System.Text.Json.JsonSerializer 支持将集合类型进行序列化,只要集合类型满足以下条件:
- 派生自 IEnumerable。
- 包含可序列化的元素。
- 派生自 IEnumerable 或 IAsyncEnumerable<T>
- 包含可序列化的元素。
序列化程序调用 GetEnumerator() 方法并写入元素。
反序列化更为复杂,并且某些集合类型不支持反序列化。
以下各节按命名空间划分,并显示序列化和反序列化支持的类型。
System.Array 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
一维数组 | ✔️ | ✔️ |
多维数组 | ❌ | ❌ |
交错数组 | ✔️ | ✔️ |
System.Collections 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
ArrayList | ✔️ | ✔️ |
BitArray | ✔️ | ❌ |
DictionaryEntry | ✔️ | ✔️ |
Hashtable | ✔️ | ✔️ |
ICollection | ✔️ | ✔️ |
IDictionary | ✔️ | ✔️ |
IEnumerable | ✔️ | ✔️ |
IList | ✔️ | ✔️ |
Queue | ✔️ | ✔️ |
SortedList | ✔️ | ✔️ |
Stack | ✔️ | ✔️ |
System.Collections.Generic 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
Dictionary<TKey,TValue> * | ✔️ | ✔️ |
HashSet<T> | ✔️ | ✔️ |
IAsyncEnumerable<T> ** | ✔️ | ✔️ |
ICollection<T> | ✔️ | ✔️ |
IDictionary<TKey,TValue> * | ✔️ | ✔️ |
IEnumerable<T> | ✔️ | ✔️ |
IList<T> | ✔️ | ✔️ |
IReadOnlyCollection<T> | ✔️ | ✔️ |
IReadOnlyDictionary<TKey,TValue> * | ✔️ | ✔️ |
IReadOnlyList<T> | ✔️ | ✔️ |
ISet<T> | ✔️ | ✔️ |
KeyValuePair<TKey,TValue> | ✔️ | ✔️ |
LinkedList<T> | ✔️ | ✔️ |
LinkedListNode<T> | ✔️ | ❌ |
List<T> | ✔️ | ✔️ |
Queue<T> | ✔️ | ✔️ |
SortedDictionary<TKey,TValue> * | ✔️ | ✔️ |
SortedList<TKey,TValue> * | ✔️ | ✔️ |
SortedSet<T> | ✔️ | ✔️ |
Stack<T> | ✔️ | ✔️ |
* 请参阅支持的密钥类型。
** 请参阅下面关于 IAsyncEnumerable<T>
的部分。
IAsyncEnumerable<T>
下面的示例使用流作为数据的任何异步源的表示形式。 源可以是本地计算机上的文件,也可以是数据库查询或 Web 服务 API 调用的结果。
流序列化
System.Text.Json
支持将 IAsyncEnumerable<T> 值序列化为 JSON 数组,如下面的示例所示:
using System.Text.Json;
namespace IAsyncEnumerableSerialize;
public class Program
{
public static async Task Main()
{
using Stream stream = Console.OpenStandardOutput();
var data = new { Data = PrintNumbers(3) };
await JsonSerializer.SerializeAsync(stream, data);
}
static async IAsyncEnumerable<int> PrintNumbers(int n)
{
for (int i = 0; i < n; i++)
{
await Task.Delay(1000);
yield return i;
}
}
}
// output:
// {"Data":[0,1,2]}
IAsyncEnumerable<T>
值仅受异步序列化方法(如 JsonSerializer.SerializeAsync)支持。
流反序列化
DeserializeAsyncEnumerable
方法支持流式反序列化,如下面的示例所示:
using System.Text;
using System.Text.Json;
namespace IAsyncEnumerableDeserialize;
public class Program
{
public static async Task Main()
{
using var stream = new MemoryStream(Encoding.UTF8.GetBytes("[0,1,2,3,4]"));
await foreach (int item in JsonSerializer.DeserializeAsyncEnumerable<int>(stream))
{
Console.WriteLine(item);
}
}
}
// output:
//0
//1
//2
//3
//4
DeserializeAsyncEnumerable
方法仅支持从根级 JSON 数组进行读取。
DeserializeAsync 方法支持 IAsyncEnumerable<T>
,但其签名不允许流式处理。 它将返回一个值作为最终结果,如下面的示例所示。
using System.Text;
using System.Text.Json;
namespace IAsyncEnumerableDeserializeNonStreaming;
public class MyPoco
{
public IAsyncEnumerable<int>? Data { get; set; }
}
public class Program
{
public static async Task Main()
{
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"{""Data"":[0,1,2,3,4]}"));
MyPoco? result = await JsonSerializer.DeserializeAsync<MyPoco>(stream)!;
await foreach (int item in result!.Data!)
{
Console.WriteLine(item);
}
}
}
// output:
//0
//1
//2
//3
//4
在此示例中,反序列化程序在返回反序列化的对象之前,它会在内存中缓冲所有 IAsyncEnumerable<T>
内容。 此行为是必需的,因为反序列化程序在返回结果之前,它需要读取整个 JSON 有效负载。
类型 | 序列化 | 反序列化 |
---|---|---|
Dictionary<TKey,TValue> * | ✔️ | ✔️ |
HashSet<T> | ✔️ | ✔️ |
IAsyncEnumerable<T> | ❌ | ❌ |
ICollection<T> | ✔️ | ✔️ |
IDictionary<TKey,TValue> * | ✔️ | ✔️ |
IEnumerable<T> | ✔️ | ✔️ |
IList<T> | ✔️ | ✔️ |
IReadOnlyCollection<T> | ✔️ | ✔️ |
IReadOnlyDictionary<TKey,TValue> * | ✔️ | ✔️ |
IReadOnlyList<T> | ✔️ | ✔️ |
ISet<T> | ✔️ | ✔️ |
KeyValuePair<TKey,TValue> | ✔️ | ✔️ |
LinkedList<T> | ✔️ | ✔️ |
LinkedListNode<T> | ✔️ | ❌ |
List<T> | ✔️ | ✔️ |
Queue<T> | ✔️ | ✔️ |
SortedDictionary<TKey,TValue> * | ✔️ | ✔️ |
SortedList<TKey,TValue> * | ✔️ | ✔️ |
SortedSet<T> | ✔️ | ✔️ |
Stack<T> | ✔️ | ✔️ |
* 请参阅支持的密钥类型。
类型 | 序列化 | 反序列化 |
---|---|---|
Dictionary<string, TValue> * | ✔️ | ✔️ |
HashSet<T> | ✔️ | ✔️ |
IAsyncEnumerable<T> | ❌ | ❌ |
ICollection<T> | ✔️ | ✔️ |
IDictionary<string, TValue> * | ✔️ | ✔️ |
IEnumerable<T> | ✔️ | ✔️ |
IList<T> | ✔️ | ✔️ |
IReadOnlyCollection<T> | ✔️ | ✔️ |
IReadOnlyDictionary<string, TValue> * | ✔️ | ✔️ |
IReadOnlyList<T> | ✔️ | ✔️ |
ISet<T> | ✔️ | ✔️ |
KeyValuePair<TKey,TValue> | ✔️ | ✔️ |
LinkedList<T> | ✔️ | ✔️ |
LinkedListNode<T> | ✔️ | ❌ |
List<T> | ✔️ | ✔️ |
Queue<T> | ✔️ | ✔️ |
SortedDictionary<string, TValue> * | ✔️ | ✔️ |
SortedList<string, TValue> * | ✔️ | ✔️ |
SortedSet<T> | ✔️ | ✔️ |
Stack<T> | ✔️ | ✔️ |
* 请参阅支持的密钥类型。
System.Collections.Immutable 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
IImmutableDictionary<TKey,TValue> ** | ✔️ | ✔️ |
IImmutableList<T> | ✔️ | ✔️ |
IImmutableQueue<T> | ✔️ | ✔️ |
IImmutableSet<T> | ✔️ | ✔️ |
IImmutableStack<T> * | ✔️ | ✔️ |
ImmutableArray<T> | ✔️ | ✔️ |
ImmutableDictionary<TKey,TValue> ** | ✔️ | ✔️ |
ImmutableHashSet<T> | ✔️ | ✔️ |
ImmutableQueue<T> | ✔️ | ✔️ |
ImmutableSortedDictionary<TKey,TValue> ** | ✔️ | ✔️ |
ImmutableSortedSet<T> | ✔️ | ✔️ |
ImmutableStack<T> * | ✔️ | ✔️ |
类型 | 序列化 | 反序列化 |
---|---|---|
IImmutableDictionary<string, TValue> ** | ✔️ | ✔️ |
IImmutableList<T> | ✔️ | ✔️ |
IImmutableQueue<T> | ✔️ | ✔️ |
IImmutableSet<T> | ✔️ | ✔️ |
IImmutableStack<T> * | ✔️ | ✔️ |
ImmutableArray<T> | ✔️ | ✔️ |
ImmutableDictionary<string, TValue> ** | ✔️ | ✔️ |
ImmutableHashSet<T> | ✔️ | ✔️ |
IImmutableList<T> | ✔️ | ✔️ |
ImmutableQueue<T> | ✔️ | ✔️ |
ImmutableSortedDictionary<string, TValue> ** | ✔️ | ✔️ |
ImmutableSortedSet<T> | ✔️ | ✔️ |
ImmutableStack<T> * | ✔️ | ✔️ |
* 请参阅支持堆栈的往返<T>。
** 请参阅支持的密钥类型。
System.Collections.Specialized 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
BitVector32 | ✔️ | ❌* |
HybridDictionary | ✔️ | ✔️ |
IOrderedDictionary | ✔️ | ❌ |
ListDictionary | ✔️ | ✔️ |
NameValueCollection | ✔️ | ❌ |
StringCollection | ✔️ | ❌ |
StringDictionary | ✔️ | ❌ |
* 反序列化 BitVector32 时将跳过 Data 属性,因为它没有公共资源库。 不会引发异常。
System.Collections.Concurrent 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
BlockingCollection<T> | ✔️ | ❌ |
ConcurrentBag<T> | ✔️ | ❌ |
ConcurrentDictionary<TKey,TValue> ** | ✔️ | ✔️ |
ConcurrentQueue<T> | ✔️ | ✔️ |
ConcurrentStack<T> * | ✔️ | ✔️ |
类型 | 序列化 | 反序列化 |
---|---|---|
BlockingCollection<T> | ✔️ | ❌ |
ConcurrentBag<T> | ✔️ | ❌ |
ConcurrentDictionary<string, TValue> ** | ✔️ | ✔️ |
ConcurrentQueue<T> | ✔️ | ✔️ |
ConcurrentStack<T> * | ✔️ | ✔️ |
* 请参阅支持堆栈的往返<T>。
** 请参阅支持的密钥类型。
System.Collections.ObjectModel 命名空间
类型 | 序列化 | 反序列化 |
---|---|---|
Collection<T> | ✔️ | ✔️ |
KeyedCollection<string, TValue> * | ✔️ | ❌ |
ObservableCollection<T> | ✔️ | ✔️ |
ReadOnlyCollection<T> | ✔️ | ❌ |
ReadOnlyDictionary<TKey,TValue> | ✔️ | ❌ |
ReadOnlyObservableCollection<T> | ✔️ | ❌ |
* 不支持非 string
密钥。
类型 | 序列化 | 反序列化 |
---|---|---|
Collection<T> | ✔️ | ✔️ |
KeyedCollection<string, TValue> * | ✔️ | ❌ |
ObservableCollection<T> | ✔️ | ✔️ |
ReadOnlyCollection<T> | ✔️ | ❌ |
ReadOnlyDictionary<string, TValue> * | ✔️ | ❌ |
ReadOnlyObservableCollection<T> | ✔️ | ❌ |
* 请参阅支持的密钥类型。
自定义集合
不在上述任一命名空间中的任何集合类型都视为自定义集合。 此类类型包括用户定义的类型和 ASP.NET Core 定义的类型。 例如,Microsoft.Extensions.Primitives 位于此组中。
只要元素类型受支持,则所有自定义类集合(派生自 IEnumerable
的任何内容)都可进行序列化。
支持反序列化的自定义集合
如果自定义集合符合以下条件,则可进行反序列化:
- 不是接口或抽象类。
- 具有无参数构造函数。
- 包含 JsonSerializer 支持的元素类型。
- 实现或继承以下一个或多个接口或类:
- 不是接口或抽象类。
- 具有无参数构造函数。
- 包含 JsonSerializer 支持的元素类型。
- 实现或继承以下一个或多个接口或类:
* 请参阅支持堆栈的往返<T>。
** 请参阅支持的密钥类型。
具有已知问题的自定义集合
以下自定义集合存在已知问题:
- ExpandoObject:请参阅 dotnet/runtime#29690。
- DynamicObject:请参阅 dotnet/runtime#1808。
- DataTable:请参阅 dotnet/docs#21366。
- Microsoft.AspNetCore.Http.FormFile:请参阅 dotnet/runtime#1559。
- Microsoft.AspNetCore.Http.IFormCollection:请参阅 dotnet/runtime#1559。
有关已知问题详细信息,请参阅 System.Text.Json 中的未解决问题。
支持的密钥类型
Dictionary
和 SortedList
的密钥支持的类型包括:
Boolean
Byte
DateTime
DateTimeOffset
Decimal
Double
Enum
Guid
Int16
Int32
Int64
Object
(仅针对序列化,并且运行时类型是此列表中的支持类型之一。)SByte
Single
String
UInt16
UInt32
UInt64
** .NET Core 3.1 中不支持 Dictionary
和 SortedList
类型的非 string
密钥。
System.Data 命名空间
System.Data 命名空间中没有用于 DataSet、DataTable 和相关类型的内置转换器。 从不受信任的输入中反序列化这些类型不安全,如安全指南中所述。 但是,可以编写自定义转换器来支持这些类型。 有关序列化并反序列化 DataTable
的示例自定义转换器代码,请参阅 RoundtripDataTable.cs。
请参阅
- System.Text.Json 概述
- 对 JsonSerializerOptions 实例进行实例化
- 启用不区分大小写的匹配
- 自定义属性名称和值
- 忽略属性
- 允许无效的 JSON
- 处理溢出 JSON,或者使用 JsonElement 或 JsonNode
- 保留引用并处理循环引用
- 反序列化为不可变类型和非公共访问器
- 多态序列化
- 从 Newtonsoft.Json 迁移到 System.Text.Json
- 自定义字符编码
- 使用 DOM、Utf8JsonReader 和 Utf8JsonWriter
- 编写用于 JSON 序列化的自定义转换器
- DateTime 和 DateTimeOffset 支持
- 如何使用源生成
- System.Text.Json API 参考
- System.Text.Json.Serialization API 参考