如何在System.Text.Json序列化时保留类型,实现object[]精准反序列化?
问题:反序列化
object[]时保留原类型信息 我在将JSON列表反序列化为object[]时,原本期望得到对应原类型的对象数组,但实际反序列化后全是System.Text.Json.JsonElement类型。我希望能反序列化为更具体的类型,但代码里没法用比object[]更具体的类型定义。请问能不能在序列化时把精确类型信息编码到JSON文本里,实现这个需求?
原代码示例
using System.Text.Json; namespace Tests.DeSerialize; class Program { public static void Main(string[] args) { object[] objs = new object[]{ 42, "foobar", false, new Example { Name = "example", } }; foreach (var obj in objs) { Console.WriteLine(obj.GetType().Name); } var serialized = JsonSerializer.Serialize(objs); Console.WriteLine(); Console.WriteLine(serialized); Console.WriteLine(); object[] deSerializedObjs = JsonSerializer.Deserialize<object[]>(serialized); foreach (var obj in deSerializedObjs) { Console.WriteLine(obj.GetType().FullName); } } } public class Example { public string Name { get; set; } public override string ToString() => $"{GetType().Name}(\"{Name}\")"; }
原输出结果
Int32 String Boolean Example [42,"foobar",false,{"Name":"example"}] System.Text.Json.JsonElement System.Text.Json.JsonElement System.Text.Json.JsonElement System.Text.Json.JsonElement
解决方案:序列化时写入类型元数据
之所以反序列化后全是JsonElement,是因为默认序列化object[]时不会写入每个元素的具体类型信息,反序列化器无法推断原类型,只能用JsonElement承载JSON数据。要解决这个问题,只需在序列化和反序列化时配置相同的JsonSerializerOptions,让JSON文本包含类型信息即可。
.NET 7及以上版本(推荐)
.NET 7+新增了IncludeTypeMetadata属性,开启后会自动为object类型的对象写入类型信息,无需手动配置派生类型:
修改后的完整代码:
using System.Text.Json; namespace Tests.DeSerialize; class Program { public static void Main(string[] args) { object[] objs = new object[]{ 42, "foobar", false, new Example { Name = "example", } }; foreach (var obj in objs) { Console.WriteLine(obj.GetType().Name); } // 配置序列化选项,开启类型元数据写入 var options = new JsonSerializerOptions { IncludeTypeMetadata = true, WriteIndented = true // 可选,格式化JSON方便查看 }; var serialized = JsonSerializer.Serialize(objs, options); Console.WriteLine(); Console.WriteLine(serialized); Console.WriteLine(); // 反序列化时使用相同的选项 object[] deSerializedObjs = JsonSerializer.Deserialize<object[]>(serialized, options); foreach (var obj in deSerializedObjs) { Console.WriteLine(obj.GetType().FullName); } } } public class Example { public string Name { get; set; } public override string ToString() => $"{GetType().Name}(\"{Name}\")"; }
运行后输出的JSON会包含类型信息:
[ { "$type": "System.Int32, System.Private.CoreLib", "$value": 42 }, { "$type": "System.String, System.Private.CoreLib", "$value": "foobar" }, { "$type": "System.Boolean, System.Private.CoreLib", "$value": false }, { "$type": "Tests.DeSerialize.Example, Tests.DeSerialize", "Name": "example" } ]
反序列化后的类型输出:
System.Int32 System.String System.Boolean Tests.DeSerialize.Example
.NET 6及更早版本
对于旧版本,需要手动配置多态序列化规则,指定object的派生类型:
using System.Text.Json; using System.Text.Json.Serialization.Metadata; namespace Tests.DeSerialize; class Program { public static void Main(string[] args) { object[] objs = new object[]{ 42, "foobar", false, new Example { Name = "example", } }; foreach (var obj in objs) { Console.WriteLine(obj.GetType().Name); } var options = new JsonSerializerOptions { WriteIndented = true }; // 配置类型解析器,添加多态规则 var resolver = new DefaultJsonTypeInfoResolver(); resolver.Modifiers.Add(typeInfo => { if (typeInfo.Type == typeof(object)) { typeInfo.PolymorphismOptions = new JsonPolymorphismOptions { TypeDiscriminatorPropertyName = "$type", // 类型标识字段名 IgnoreUnrecognizedTypeNames = false, DerivedTypes = { new JsonDerivedType(typeof(int)), new JsonDerivedType(typeof(string)), new JsonDerivedType(typeof(bool)), new JsonDerivedType(typeof(Example)) } }; } }); options.TypeInfoResolver = resolver; var serialized = JsonSerializer.Serialize(objs, options); Console.WriteLine(); Console.WriteLine(serialized); Console.WriteLine(); object[] deSerializedObjs = JsonSerializer.Deserialize<object[]>(serialized, options); foreach (var obj in deSerializedObjs) { Console.WriteLine(obj.GetType().FullName); } } } public class Example { public string Name { get; set; } public override string ToString() => $"{GetType().Name}(\"{Name}\")"; }
注意事项
- 类型信息包含程序集名称,确保反序列化的环境中存在对应的类型和程序集。
- 自定义类型(如示例中的
Example)需要在序列化和反序列化两端都能被访问到。 - .NET 7+的
IncludeTypeMetadata会自动处理所有可序列化类型,比手动配置更便捷。
内容的提问来源于stack exchange,提问作者user20376912
相关产品推荐
相关产品推荐

