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

.NET 8 PublishAot编译下Newtonsoft.Json反序列化构造函数找不到问题

问题描述

我使用以下代码进行JSON反序列化:

string json = File.ReadAllText($"./assets/JSON/{mapName}.json");
Console.WriteLine(json);
var gridMapData = JsonConvert.DeserializeObject<GridMapData>(json);

Release模式下代码运行正常,但开启PublishAot原生编译后(项目配置如下),抛出Newtonsoft.Json.JsonSerializationException: Unable to find a constructor.异常。已确认JSON内容读取正常,且JSON结构与反序列化类未做任何改动。

项目配置:

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>net8.0</TargetFramework>
  <ImplicitUsings>enable</ImplicitUsings>
  <Nullable>enable</Nullable>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>
  <Platforms>AnyCPU;x64;x86</Platforms>
  <ApplicationManifest>app.manifest</ApplicationManifest>
  <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>

我尝试过修改GridMapData类,包括添加带参构造函数、无参构造函数、标记[JsonConstructor]属性,但均未解决问题:

public class GridMapData
{
    public int width;
    public int height;
    public Dictionary<string, int> cells;

    // 尝试过的代码(已注释)
    //public GridMapData(int Width, int Height, Dictionary<string, int> Cells)
    //{
    //    this.width = Width;
    //    this.height = Height;
    //    this.cells = Cells;
    //}
    //public GridMapData() { }

    //[JsonConstructor]
    //public GridMapData() { }
}
原因与解决方法

核心原因

PublishAOT是.NET的原生AOT编译技术,会在编译阶段执行静态代码分析,将未被直接引用的类型、成员、构造函数等从最终程序中裁剪。Newtonsoft.Json依赖反射动态查找构造函数,这类反射调用无法被AOT的静态分析识别,导致无参构造函数被意外裁剪,最终抛出找不到构造函数的异常。

具体解决步骤

1. 保留类的公共无参构造函数

确保GridMapData类拥有明确的公共无参构造函数,这是Newtonsoft.Json反序列化的基础要求:

public class GridMapData
{
    public int width;
    public int height;
    public Dictionary<string, int> cells;

    // 必须保留的公共无参构造函数
    public GridMapData() { }
}

2. 添加AOT编译保留规则(Runtime Directives)

在项目中创建rd.xml文件,告诉AOT编译器不要裁剪GridMapData的构造函数和成员:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <Assembly Name="你的项目程序集名称" Dynamic="Required All">
      <Type Name="GridMapData" Dynamic="Required All">
        <Method Name=".ctor" Dynamic="Required All"/> <!-- 保留无参构造函数 -->
        <Field Name="width" Dynamic="Required All"/>
        <Field Name="height" Dynamic="Required All"/>
        <Field Name="cells" Dynamic="Required All"/>
      </Type>
    </Assembly>
  </Application>
</Directives>

将你的项目程序集名称替换为实际的项目名称(通常与项目文件夹名一致),然后在项目文件中引入该文件:

<ItemGroup>
  <RdXmlFile Include="rd.xml" />
</ItemGroup>

3. 替代方案:改用System.Text.Json(推荐)

Newtonsoft.Json对AOT的支持有限,.NET 8的System.Text.Json原生兼容AOT编译,无需额外配置(只要类符合AOT要求)。替换为以下代码即可:

using System.Text.Json;

string json = File.ReadAllText($"./assets/JSON/{mapName}.json");
var gridMapData = JsonSerializer.Deserialize<GridMapData>(json);

同样需要确保GridMapData拥有公共无参构造函数,若使用带参构造函数,可通过[JsonConstructor]标记指定反序列化用的构造函数。

4. 临时应急方案

如果暂时无法修改配置或更换序列化库,可在代码中显式引用无参构造函数,让AOT编译器检测到它并保留:

// 在程序启动或某个必定执行的代码块中添加
_ = new GridMapData();

此方法不够优雅,仅适合临时测试场景。

内容的提问来源于stack exchange,提问作者brenoca

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:05:08