Json.net`JsonConstructor`构造函数参数名称
通过JsonConstructor
使用特定的.ctor反序列化IList
属性时,参数名称必须与原始 Json名称匹配,并且不使用这些属性上的JsonProperty
映射。
例:
SpokenLanguages
参数始终为null,因为它与spoken_languages
不匹配,但有一个JsonProperty
映射它:
public partial class AClass : ISomeBase { public AClass() { } [JsonConstructor] public AClass(IList SysTypes, IList production_countries, IList SpokenLanguages) { this.Genres = SysTypes?.ToList(); this.ProductionCountries = production_countries?.ToList(); this.SpokenLanguages = SpokenLanguages?.ToList(); } public int Id { get; set; } public IList Genres { get; set; } [JsonProperty("production_countries")] public IList ProductionCountries { get; set; } [JsonProperty("spoken_languages")] public IList SpokenLanguages { get; set; } }
这只是Json.Net
如何调用构造函数的“限制”,还是我缺少的东西。
仅供参考:我是通过Rosyln生成所有这些的代码,我不打算JsonConverter
生成每种类型的JsonConverter
…
当Json.NET调用参数化构造函数时,它会按名称将JSON属性与构造函数参数匹配。 但是,对于也与类型成员对应的JSON属性,它使用哪个名称 – 成员名称,或者由JsonPropertyAttribute.PropertyName
指定的覆盖类型成员名称?
看来你希望它们都匹配,因为你的参数命名约定是不一致的:
-
构造函数参数
production_countries
匹配重写的属性名称:[JsonProperty("production_countries")] public IList
ProductionCountries { get; set; } -
构造函数参数
IList
匹配reflection的名称而不是重写的属性名称:SpokenLanguages [JsonProperty("spoken_languages")] public IList
SpokenLanguages { get; set; } -
IList
都不匹配(这是问题中的拼写错误吗?)SysTypes
但是,重要的是JSON文件本身中的属性名称和JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()
显示的构造函数参数名称 。 该算法的简化版本如下:
- 从JSON文件中读取属性名称。
- 找到最接近的匹配构造函数参数(如果有)。
- 找到最接近的匹配成员名称(如果有)。
- 如果JSON属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
- 但如果没有,则反序列化为适当的成员类型,并在构造后设置成员值。
(当JSON属性与两者兼容时,实现变得复杂,并且开发人员期望在构造函数中设置时,应该尊重添加到成员的[JsonProperty(Required = Required.Always)]
。)
因此构造函数参数production_countries
将匹配JSON中名为"production_countries"
的值,而构造函数参数SpokenLanguages
将不匹配名为"spoken_languages"
的JSON值。
那么,如何成功反序列化您的类型? 首先,您可以使用[JsonProperty(overrideName)]
标记构造函数参数,以覆盖反序列化期间使用的构造函数名称:
public partial class AClass : ISomeBase { public AClass() { } [JsonConstructor] public AClass([JsonProperty("Genres")] IList SysTypes, IList production_countries, [JsonProperty("spoken_languages")] IList SpokenLanguages) { this.Genres = SysTypes == null ? null : SysTypes.Cast().ToList(); this.ProductionCountries = production_countries == null ? null : production_countries.Cast().ToList(); this.SpokenLanguages = SpokenLanguages == null ? null : SpokenLanguages.Cast().ToList(); }
其次,由于您似乎使用构造函数将包含接口的集合中的项目反序列化为具体对象,因此您可以考虑使用基于CustomCreationConverter
的单个通用转换器作为ItemConverter
:
public partial class AClass : ISomeBase { public AClass() { } public int Id { get; set; } [JsonProperty(ItemConverterType = typeof(CustomCreationConverter))] public IList Genres { get; set; } [JsonProperty("production_countries", ItemConverterType = typeof(CustomCreationConverter))] public IList ProductionCountries { get; set; } [JsonProperty("spoken_languages", ItemConverterType = typeof(CustomCreationConverter))] public IList SpokenLanguages { get; set; } } public class CustomCreationConverter : CustomCreationConverter where TSerialized : T, new() { public override T Create(Type objectType) { return new TSerialized(); } }
显示两个选项的示例小提琴 。