Json.net `JsonConstructor` constructor parameter names(Json.net `JsonConstructor` 构造函数参数名称)
问题描述
当通过 JsonConstructor
使用特定 .ctor 反序列化 IList
属性时,参数名称必须与 原始 Json 名称和未使用这些属性上的 JsonProperty
映射.
When using a specific .ctor via JsonConstructor
for deserializing IList<ISomeInterface>
properties, the parameter names must match the original Json names and the JsonProperty
mapping on those properties are not used.
SpokenLanguages
参数始终为空,因为它与 spoken_languages
不匹配,但有一个 JsonProperty
映射它:
SpokenLanguages
parameter is always null since it does not match spoken_languages
, but there is a JsonProperty
mapping it:
public partial class AClass : ISomeBase
{
public AClass() { }
[JsonConstructor]
public AClass(IList<SysType> SysTypes, IList<ProductionCountry> production_countries, IList<SpokenLanguage> SpokenLanguages)
{
this.Genres = SysTypes?.ToList<IGenre>();
this.ProductionCountries = production_countries?.ToList<IProductionCountry>();
this.SpokenLanguages = SpokenLanguages?.ToList<ISpokenLanguage>();
}
public int Id { get; set; }
public IList<IGenre> Genres { get; set; }
[JsonProperty("production_countries")]
public IList<IProductionCountry> ProductionCountries { get; set; }
[JsonProperty("spoken_languages")]
public IList<ISpokenLanguage> SpokenLanguages { get; set; }
}
这只是一个限制"吗?Json.Net
如何调用构造函数或者我缺少什么.
Is this just a "limitation" of how Json.Net
calls the constructor or is there something I am missing.
仅供参考:我是通过 Rosyln 生成所有这些的代码,我不打算为此生成每个类型的 JsonConverter
...
FYI: I am code generating all this via Rosyln and am not looking at generating a JsonConverter
for each type for this...
推荐答案
当 Json.NET 调用参数化构造函数时,它会按名称将 JSON 属性与构造函数参数匹配,使用序数忽略大小写匹配.但是,对于也对应于类型成员的 JSON 属性,它使用哪个名称 - 成员名称,或由 JsonPropertyAttribute.PropertyName
?
When Json.NET invokes a parameterized constructor, it matches JSON properties to constructor arguments by name, using an ordinal case-ignoring match. However, for JSON properties that also correspond to type members, which name does it use - the member name, or the override type member name specified by JsonPropertyAttribute.PropertyName
?
您似乎希望它在 both 上匹配,因为您的参数命名约定不一致:
It appears you are hoping it matches on both, since your argument naming conventions are inconsistent:
构造函数参数
production_countries
匹配被覆盖的属性名称:
The constructor argument
production_countries
matches the overridden property name:
[JsonProperty("production_countries")]
public IList<IProductionCountry> ProductionCountries { get; set; }
构造函数参数IList
匹配反映的名称而不是覆盖的属性名称:
The constructor argument IList<SpokenLanguage> SpokenLanguages
matches the reflected name rather than the overridden property name:
[JsonProperty("spoken_languages")]
public IList<ISpokenLanguage> SpokenLanguages { get; set; }
IList
都不匹配(这是问题中的错字吗?)
IList<SysType> SysTypes
matches neither (is this a typo in the question?)
然而,重要的是 JSON 文件本身中的属性名称 和 构造函数参数名称,如 JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()
.该算法的简化版本如下:
However, what matters is the property name in the JSON file itself and the constructor argument name as shown in JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()
. A simplified version of the algorithm is as follows:
- 从 JSON 文件中读取属性名称.
- 找到最接近的匹配构造函数参数(如果有).
- 找到最匹配的成员名称(如果有).
- 如果 JSON 属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
- 但如果不是,则反序列化为适当的成员类型,并在构造后设置成员值.
(当 JSON 属性与 both 匹配并且开发人员期望,例如 [JsonProperty(Required = Required.Always)]
在构造函数中设置时应尊重添加到成员的内容.)
(The implementation becomes complex when a JSON property matches both and developers expect that, for instance, [JsonProperty(Required = Required.Always)]
added to the member should be respected when set in the constructor.)
因此构造函数参数 production_countries
将匹配 JSON 中名为 production_countries"
的值,而构造函数参数 SpokenLanguages
将 不匹配名为 spoken_languages"
的 JSON 值.
Thus the constructor argument production_countries
will match a value named "production_countries"
in the JSON, while the constructor argument SpokenLanguages
will not match a JSON value named "spoken_languages"
.
那么,如何成功反序列化你的类型呢?首先,您可以使用 [JsonProperty(overrideName)]
标记构造函数参数以覆盖反序列化期间使用的构造函数名称:
So, how to deserialize your type successfully? Firstly, you could mark the constructor parameters with [JsonProperty(overrideName)]
to override the constructor name used during deserialization:
public partial class AClass : ISomeBase
{
public AClass() { }
[JsonConstructor]
public AClass([JsonProperty("Genres")] IList<SysType> SysTypes, IList<ProductionCountry> production_countries, [JsonProperty("spoken_languages")] IList<SpokenLanguage> SpokenLanguages)
{
this.Genres = SysTypes == null ? null : SysTypes.Cast<IGenre>().ToList();
this.ProductionCountries = production_countries == null ? null : production_countries.Cast<IProductionCountry>().ToList();
this.SpokenLanguages = SpokenLanguages == null ? null : SpokenLanguages.Cast<ISpokenLanguage>().ToList();
}
其次,由于您似乎使用构造函数将包含接口的集合中的项目反序列化为具体对象,您可以考虑使用基于 CustomCreationConverter
作为 ItemConverter
:
Secondly, since you seem to be using the constructor to deserialize items in collections containing interfaces as concrete objects, you could consider using a single generic converter based on CustomCreationConverter
as an ItemConverter
:
public partial class AClass : ISomeBase
{
public AClass() { }
public int Id { get; set; }
[JsonProperty(ItemConverterType = typeof(CustomCreationConverter<IGenre, SysType>))]
public IList<IGenre> Genres { get; set; }
[JsonProperty("production_countries", ItemConverterType = typeof(CustomCreationConverter<IProductionCountry, ProductionCountry>))]
public IList<IProductionCountry> ProductionCountries { get; set; }
[JsonProperty("spoken_languages", ItemConverterType = typeof(CustomCreationConverter<ISpokenLanguage, SpokenLanguage>))]
public IList<ISpokenLanguage> SpokenLanguages { get; set; }
}
public class CustomCreationConverter<T, TSerialized> : CustomCreationConverter<T> where TSerialized : T, new()
{
public override T Create(Type objectType)
{
return new TSerialized();
}
}
小提琴示例显示了这两个选项.
这篇关于Json.net `JsonConstructor` 构造函数参数名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:Json.net `JsonConstructor` 构造函数参数名称
基础教程推荐
- MS Visual Studio .NET 的替代品 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01