使用 Json.NET 序列化时如何应用重新映射所有属性名称的一般规则?

How to apply a general rule for remapping all property names when serializing with Json.NET?(使用 Json.NET 序列化时如何应用重新映射所有属性名称的一般规则?)

本文介绍了使用 Json.NET 序列化时如何应用重新映射所有属性名称的一般规则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将 Json 对象反序列化为 .Net type 时,如果字段名称不匹配,我发现您可以使用 装饰您的 type 的属性>[JsonProperty(PropertyName = "name")]

When deserializing a Json object into a .Net type, if the field names don't match up I found you can decorate your type's properties with [JsonProperty(PropertyName = "name")]

这对于一些不匹配的属性来说很好,但有没有办法设置约定或规则?

This is fine and dandy for a couple of properties that don't match up, but is there a way to set a convention or rule?

Json

{
  "Job": [
    {
      "Job #": "1",
      "Job Type": "A",
    }
  ]
}

C#

    [JsonProperty(PropertyName = "Job Type")]
    public string JobType { get; set; }

    [JsonProperty(PropertyName = "Job #")]
    public string JobNumber { get; set; }

我有许多使用相似名称的字段,我想弄清楚,有没有办法告诉设置规则以始终删除空格(EG:Job Type -> JobType)并将 # 替换为 Number(例如:Job # -> JobNumber)?

I have many fields using similar names, what I would like to figure out, is there a way to tell to set a rule to always remove spaces (EG: Job Type -> JobType) and replace # with Number (eg: Job # -> JobNumber)?

看起来自定义 ContractResolver 可能是唯一的解决方案,但我似乎无法弄清楚如何使用它来提取空格并将#"替换为Number".谁有参考例子?

It looks like a custom ContractResolver might be the only solution, but I can't seem to figure out how to go about using it to pluck out spaces and replace "#" with "Number". Does anyone have a reference example?

或者,我希望有一个很好的简单解决方案,但我忽略了.

Or, I'm hoping there's a nice simple solution that I've overlooked.

附:也接受关于更好标题的建议.

P.S. Also accepting suggestions for a better title.

推荐答案

假设你正在使用 Json.NET 9.0.1 或更高版本,这可以通过自定义 NamingStrategy.例如,这是一个基于 <代码>SnakeCaseNamingStrategyStringUtils.ToSnakeCase() 作者:James Newton-King:

Assuming you are working with Json.NET 9.0.1 or later, this can be done with a custom NamingStrategy. For instance, here's one based on SnakeCaseNamingStrategy and StringUtils.ToSnakeCase() by James Newton-King:

public class CustomNamingStrategy : NamingStrategy
{
    public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames)
    {
        ProcessDictionaryKeys = processDictionaryKeys;
        OverrideSpecifiedNames = overrideSpecifiedNames;
    }

    public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames)
        : this(processDictionaryKeys, overrideSpecifiedNames)
    {
        ProcessExtensionDataNames = processExtensionDataNames;
    }

    public CustomNamingStrategy()
    {
    }

    protected override string ResolvePropertyName(string name)
    {
        return SpaceWords(name);
    }

    enum WordState
    {
        Start,
        Lower,
        Upper,
        NewWord
    }

    static string SpaceWords(string s)
    {
        // Adapted from StringUtils.ToSnakeCase()
        // https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/StringUtils.cs#L191
        // 
        // Copyright (c) 2007 James Newton-King
        //
        // Permission is hereby granted, free of charge, to any person
        // obtaining a copy of this software and associated documentation
        // files (the "Software"), to deal in the Software without
        // restriction, including without limitation the rights to use,
        // copy, modify, merge, publish, distribute, sublicense, and/or sell
        // copies of the Software, and to permit persons to whom the
        // Software is furnished to do so, subject to the following
        // conditions:
        //
        // The above copyright notice and this permission notice shall be
        // included in all copies or substantial portions of the Software.
        //
        // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
        // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
        // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
        // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
        // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
        // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
        // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
        // OTHER DEALINGS IN THE SOFTWARE.

        char wordBreakChar = ' ';

        if (string.IsNullOrEmpty(s))
        {
            return s;
        }

        StringBuilder sb = new StringBuilder();
        WordState state = WordState.Start;

        for (int i = 0; i < s.Length; i++)
        {
            if (s[i] == ' ')
            {
                if (state != WordState.Start)
                {
                    state = WordState.NewWord;
                }
            }
            else if (char.IsUpper(s[i]))
            {
                switch (state)
                {
                    case WordState.Upper:
                        bool hasNext = (i + 1 < s.Length);
                        if (i > 0 && hasNext)
                        {
                            char nextChar = s[i + 1];
                            if (!char.IsUpper(nextChar) && nextChar != ' ')
                            {
                                sb.Append(wordBreakChar);
                            }
                        }
                        break;
                    case WordState.Lower:
                    case WordState.NewWord:
                        sb.Append(wordBreakChar);
                        break;
                }

                sb.Append(s[i]);

                state = WordState.Upper;
            }
            else if (s[i] == wordBreakChar)
            {
                sb.Append(wordBreakChar);
                state = WordState.Start;
            }
            else
            {
                if (state == WordState.NewWord)
                {
                    sb.Append(wordBreakChar);
                }

                sb.Append(s[i]);
                state = WordState.Lower;
            }
        }

        sb.Replace("Number", "#");
        return sb.ToString();
    }
}

然后你可以将它应用到你的类型上,如下所示:

Then you can apply it to your type as follows:

[JsonObject(NamingStrategyType = typeof(CustomNamingStrategy))]
public class RootObject
{
    public string JobType { get; set; }

    public string JobNumber { get; set; }

    public int JobItemCount { get; set; }

    public string ISOCode { get; set; }

    public string SourceXML { get; set; }
}

而生成的JSON会如下:

And the JSON generated will be as follows:

{
  "Job Type": "job type",
  "Job #": "01010101",
  "Job Item Count": 3,
  "ISO Code": "ISO 9000",
  "Source XML": "c:	emp.xml"
}

注意事项:

  • 如果您希望该策略应用于已经通过 JsonPropertyAttribute.PropertyName,设置 NamingStrategy.OverrideSpecifiedNames == true.

要将您的命名策略应用于所有类型,而不是在每个对象上设置,您可以在 DefaultContractResolver.NamingStrategy,然后在 JsonSerializerSettings.ContractResolver.

To apply your naming strategy to all types rather than setting it on each object, you can set the naming strategy in DefaultContractResolver.NamingStrategy, then set the contract resolver in JsonSerializerSettings.ContractResolver.

命名策略从 c# 属性名映射到 JSON 属性名,反之则不然.因此,您需要插入空格而不是将它们拔出"并将Number"替换为#".然后映射由合约解析器缓存,并在反序列化期间进行反向查找.

The naming strategy maps from the c# property name to the JSON property name, not vice versa. Thus you need to insert spaces rather than "pluck them out" and replace "Number" with "#". The mapping is then cached by the contract resolver and a reverse lookup is done during deserialization.

这篇关于使用 Json.NET 序列化时如何应用重新映射所有属性名称的一般规则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:使用 Json.NET 序列化时如何应用重新映射所有属性名称的一般规则?