gpt4 book ai didi

c# - 为什么 Json.NET 试图反序列化我的 get only 属性?

转载 作者:行者123 更新时间:2023-11-30 20:26:52 24 4
gpt4 key购买 nike

我一直在尝试以某种方式序列化和反序列化我的对象,以便我能够指定要序列化但不反序列化某些属性。

示例代码如下:

public interface ISupYo
{
string Hi { get; }
}
public class SupYo : ISupYo
{
public string Hi { get; } = "heya";
}

public interface ISup
{
int hiyo { get; }
}
public class Sup : ISup
{
public Sup(int hiyo)
{
this.hiyo = hiyo;
}

public int hiyo { get; }
public ISupYo yo => new SupYo();
}

var myNewSup = JsonConvert.SerializeObject(new Sup(2));
var mySup = JsonConvert.DeserializeObject<Sup>(myNewSup);

如果我从类 Sup 中删除构造函数,一切都很好。

但是由于 json.net 试图构建接口(interface) ISupYo...,原样反序列化失败并出现以下错误...

Newtonsoft.Json.JsonSerializationException: 'Could not create an instance of type Scratchpad.Program+ISupYo. Type is an interface or abstract class and cannot be instantiated. Path 'yo.Hi', line 1, position 21.'

我试过这里的说明 Serialize Property, but Do Not Deserialize Property in Json.Net但反序列化以同样的方式失败。

以这种方式使用 JsonConverter http://pmichaels.net/tag/type-is-an-interface-or-abstract-class-and-cannot-be-instantiated/成功,在序列化/反序列化期间指定typeNameHandling和格式处理也是如此

为什么使用/不使用默认构造函数之间存在这种差异?

最佳答案

原因您看到的异常是 Json.NET 功能的不幸交互:

  1. 如果被反序列化的对象具有只读引用类型成员,Json.NET 将 populate它的值的内容来自 JSON 流,只要它是预先分配的。即使成员的声明类型是抽象类型或接口(interface)也是如此,因为返回的真实对象显然必须是具体的。

    示例 .Net fiddle 演示此 here .

  2. 如果被反序列化的对象指定使用参数化构造函数,Json.NET 将从 JSON 流中读取整个对象,将所有属性反序列化为其声明的类型,然后按名称将反序列化的属性与构造函数参数匹配 (模数大小写)并使用匹配的反序列化属性构造对象。最后,任何不匹配的属性都将被设置回对象。

  3. Json.NET 是一个单 channel 反序列化器,永远不会返回重新读取之前读取的 JSON token 。

遗憾的是,前两个功能不能很好地结合使用。如果必须在构造类型之前反序列化参数化类型的所有属性,则不可能从 JSON 流填充预分配的只读成员,因为流已被读取。

更糟糕的是,Json.NET 似乎试图反序列化 对应构造函数参数但 对应只读成员的 JSON 属性,即使它可能应该跳过它们。由于您的 ISupYo yo 成员是一个接口(interface),您会看到异常(除非您指定了 TypeNameHandling,在这种情况下您没有指定)。这可能是一个错误;你可以report an issue如果你想。具体问题好像是JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()缺少检查以查看非构造函数属性是否为 Writable .

最简单的解决方法需要使用特殊的 JsonConverter ,因为上面提到的 ResolvePropertyAndCreatorValues() 会检查是否存在转换器。首先介绍一下SkipDeserializationConverter:

public class SkipDeserializationConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
reader.Skip();
return existingValue;
}

public override bool CanWrite { get { return false; } }

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

并将其应用于您的类型,如下所示:

[JsonConverter(typeof(SkipDeserializationConverter))]
public ISupYo yo { get { return new SupYo(); } }

转换器只是跳过当前正在读取的 token 的所有子代,而不尝试反序列化任何内容。使用它可能比使用 TypeNameHandling 更可取,因为后者会引入安全风险,如 TypeNameHandling caution in Newtonsoft Json 中所述。 .

sample 加工 .Net fiddle .

关于c# - 为什么 Json.NET 试图反序列化我的 get only 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49411617/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com