Json.net `JsonConstructor` 构造函数参数名称 [英] Json.net `JsonConstructor` constructor parameter names

查看:17
本文介绍了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;SpokenLanguages 匹配反映的名称而不是覆盖的属性名称:

  • 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; }
    

  • IListSysTypes 都不匹配(这是问题中的错字吗?)

  • 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:

    1. 从 JSON 文件中读取属性名称.
    2. 找到最接近的匹配构造函数参数(如果有).
    3. 找到最匹配的成员名称(如果有).
    4. 如果 JSON 属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
    5. 但如果不是,则反序列化为适当的成员类型,并在构造后设置成员值.

    (当 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` 构造函数参数名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆