You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:31:21