【问题标题】:Deserialize issue with JSON.NET on UWP, using ImmutableList (only Release mode)使用 ImmutableList 反序列化 UWP 上 JSON.NET 的问题(仅限发布模式)
【发布时间】:2024-01-11 08:22:01
【问题描述】:

我遇到了一种恼人且奇怪的行为,这种行为在调试模式和发布模式之间有所不同。 所以,我们在 UWP 10.0.10586 上,使用 JSON.NET 7.0.1

我有一个看起来像这样的模型类:

[JsonObject]
public class RootObject
{
    [JsonProperty]
    public Profile ProfileInfo { get; set; } = new Profile();

    [JsonProperty]
    public ImmutableList<Info> AdditionalInfo { get; set; } = ImmutableList.Create<Info>();
}

然后我尝试反序列化一个json:

var rootObject = JsonConvert.DeserializeObject<RootObject>(json);

这在 Debug 模式下完美运行,但在 Release 模式下不会反序列化 AdditionalInfo(列表为空)。

如果我使用 IEnumerable 或 IList 而不是 ImmutableList,它也可以工作,但我想知道这种行为是否有原因,或者可能是 JSON.NET 错误。

【问题讨论】:

    标签: c# json serialization json.net uwp


    【解决方案1】:

    您很可能遇到 .NET Native 的运行时异常之一。为了正确诊断这一点,我建议为项目的 DEBUG 配置启用 .NET Native 编译(Project properties > BUILD > Enable .Net Native 复选框)。然后,将调试器设置为在第一次出现异常时停止。

    现在,当您运行时,您可能会看到 MissingMetadataException 或有关序列化的信息,但因为您处于调试状态,您会得到不错的异常字符串。如果您可以移至更新 1,则消息会更好一些。您很可能需要在 Default.rd.xml 文件中添加一些内容。

    【讨论】:

    • 好的,这帮助我至少获得了一个例外,而不是默默地改变行为。虽然异常是“JsonSerializerException” - 无法找到用于类型 ImmutableList 的构造函数,但要清楚:导致调试:i.imgur.com/8JriPfP.png 使用 .NET Native 进行调试:i.imgur.com/uGT7OEt.png 关于我的任何提示如果这是问题,应该添加到 Default.rx.xml 吗?
    【解决方案2】:

    为了反射激活 ImmutableCollection,Json.NET 反射 ImmutableCollection 尝试查找 CreateRange 方法。由于使用非平凡反射,.NET Native 编译器无法预测这一点,因此此查找失败。来自 Json.NET 的错误消息非常不幸,因为它并没有告诉您无法通过反射找到 ImmutableCollection.CreateRange 才是真正的问题。

    现在我们知道这是问题所在,我们可以使用http://dotnet.github.io/native/troubleshooter/type.html 的工具来构造一段 RD.XML 来修复它。修复它的 RD.XML 是:

    <Type Name="System.Collections.Immutable.ImmutableList" Dynamic="Required All" />
    

    【讨论】:

    • 我不确定该将 rd.xml 放在哪里。我正在开发一个库(dll)项目。我应该将 rd.xml 放到库项目还是应用程序项目中?这有点令人困惑,因为我创建的所有项目都有一个 Default.rd.xml。我不确定应用程序如何使用这些 rd.xml 文件。是否有一些文档可以解释这一点?
    【解决方案3】:

    我们遇到了类似的问题,但是 .rd.xml 技巧并没有解决它。该代码将 JSON 反序列化为动态对象,在调试模式下运行良好,并且在将 UWP 更新到 10.0.15138 之前在发布模式下运行。但是现在它在发布模式下崩溃了。

    这是修复之前的行(不起作用):

    dynamic obj = JsonConvert.DeserializeObject(rpcStatus);
    

    解决方法是将 ExpandoObject 指定为 Newtonsoft 要反序列化的类型,就像这样(确实有效):

    dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(rpcStatus);
    

    【讨论】: