Newtonsoft JsonConvert.SerializeObject如果名称为大写,则忽略JsonProperty

Newtonsoft JsonConvert.SerializeObject如果名称为大写,则忽略JsonProperty

问题描述:

我希望能够使用CamelCasePropertyNameContractResolver,但要为特定的属性名称覆盖它.为此,我使用JsonProperty属性.除非我选择的名称全为大写,否则此方法工作正常.有任何想法出什么问题或如何解决吗?

I want to be able to use the CamelCasePropertyNameContractResolver but override it for specific property names. For this, I use the JsonProperty attribute. This works fine except when the name that I choose is fully uppercase. Any ideas what's wrong or how to get around it?

在下面的示例中,当我不使用CamelCasePropertyNameContractResolver时,Bar被序列化为"BAR",但是当我使用解析器时,被序列化为"bar".在两种情况下,FooCamelCaseProperty均已正确序列化.

In the example below, Bar is serialized to "BAR" when I don't use the CamelCasePropertyNameContractResolver, but is serialized to "bar" when I do use the resolver. Foo and CamelCaseProperty are serialized correctly in both scenarios.

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ConsoleTester
{
    class Program
    {
        static void Main(string[] args)
        {
            var foo = new FooBar {CamelCaseProperty = "test", Foo = "test", Bar = "test" };
            var output = JsonConvert.SerializeObject(foo);
            // output "CamelCaseProperty", "fOO", "BAR"

            var output2 = JsonConvert.SerializeObject(foo, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
            // output "camelCaseProperty", "fOO", "bar"
        }
    }

    public class FooBar
    {
        public string CamelCaseProperty { get; set; }
        [JsonProperty("fOO")]
        public string Foo { get; set; }
        [JsonProperty("BAR")]
        public string Bar { get; set; }
    }
}

原因,您看到的原因是CamelCasePropertyNamesContractResolver旨在覆盖明确设置属性名称,如

The reason you are seeing this is that CamelCasePropertyNamesContractResolver is intentionally designed to override the casing of dictionary keys and explicitly set property names, as can be see from the reference source:

public CamelCasePropertyNamesContractResolver()
{
    NamingStrategy = new CamelCaseNamingStrategy
    {
        ProcessDictionaryKeys = true,
        OverrideSpecifiedNames = true
    };
}

如果您不希望这样做,则可以使用多个选项来防止在不创建自己的自定义合同解析器类型的情况下使用显式名称进行大小写.

If you don't want that, you have several options to prevent casing of explicit names without creating your own custom contract resolver type.

首先,您可以使用 NamingStrategy = new CamelCaseNamingStrategy() :

Firstly, you could serialize using a DefaultContractResolver with NamingStrategy = new CamelCaseNamingStrategy():

var settings = new JsonSerializerSettings 
{ 
    ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }
};
var output2 = JsonConvert.SerializeObject(foo, settings);

这会将 CamelCaseNamingStrategy.OverrideSpecifiedNames 保留为默认值.

This leaves CamelCaseNamingStrategy.OverrideSpecifiedNames at its default value of false.

其次,如果您无权访问框架的合同解析器,则可以设置

Secondly, if you don't have access to the contract resolver of your framework, you could set JsonPropertyAttribute.NamingStrategyType = typeof(DefaultNamingStrategy) on specific properties, like so:

public class FooBar
{
    public string CamelCaseProperty { get; set; }

    [JsonProperty("fOO")]
    public string Foo { get; set; }

    [JsonProperty("BAR", NamingStrategyType = typeof(DefaultNamingStrategy))]
    public string Bar { get; set; }
}

第三次,如果您想让整个对象忽略当前合同解析器的命名策略,则可以应用

Thirdly, if you want your entire object to ignore the naming strategy of the current contract resolver, you can apply [JsonObject(NamingStrategyType = typeof(TNamingStrategy))] to your object:

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class FooBar
{
    public string CamelCaseProperty { get; set; }

    [JsonProperty("fOO")]
    public string Foo { get; set; }

    [JsonProperty("BAR")]
    public string Bar { get; set; }
}

注意:

  • 虽然也可以修改在全球范围内共享合同信息每种类型的所有实例,如果您的应用程序尝试使用多个CamelCasePropertyNamesContractResolver实例,则可能导致意外的副作用. DefaultContractResolver不存在这样的问题,因此在需要对大小写逻辑进行任何自定义时,使用起来更安全.

  • While it is also possible to modify the NamingStrategy of an instance of CamelCasePropertyNamesContractResolver, since the latter shares contract information globally across all instances of each type, this can lead to unexpected side-effects if your application tries to use multiple instances of CamelCasePropertyNamesContractResolver. No such problem exists with DefaultContractResolver, so it is safer to use when any customization of casing logic is required.

使用或子类化DefaultContractResolver时,您可能想要缓存合同解析器,以获得最佳性能,因为它不会在每种类型的所有实例之间全局共享合同信息.

When using or subclassing DefaultContractResolver, you may want to cache the contract resolver for best performance, since it does not share contract information globally across all instances of each type.

我不知道为什么Json.NET的驼峰式案例解析器旨在重写指定的名称,这可能是出于历史原因.

I don't know why Json.NET's camel case resolver is designed to override specified names, it may be for historical reasons.

命名策略最初是在 Json.NET 9.0中引入的. 1 ,因此此答案仅适用于该版本及更高版本.

Naming strategies were first introduced in Json.NET 9.0.1 so this answer works only for that version and later.