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

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

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

 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被有意设计为覆盖字典键的大小并显式设置属性名称 ,从参考源可以看出:

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

如果您不想这样做,则可以使用多个选项来防止显式名称的大小写,而无需创建自己的自定义合约解析程序类型。

首先 ,您可以使用带有NamingStrategy = new CamelCaseNamingStrategy()DefaultContractResolver进行序列化:

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

这使得CamelCaseNamingStrategy.OverrideSpecifiedNames的默认值为false

其次 ,如果您无权访问框架的合约解析程序,则可以在特定属性上设置JsonPropertyAttribute.NamingStrategyType = typeof(DefaultNamingStrategy) ,如下所示:

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

第三 ,如果您希望整个对象忽略当前合约解析器的命名策略,可以将[JsonObject(NamingStrategyType = typeof(TNamingStrategy))]应用于您的对象:

 [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实例的NamingStrategy ,因为后者在每种类型的所有实例之间全局共享合同信息 ,如果您的应用程序尝试使用CamelCasePropertyNamesContractResolver多个实例,这可能会导致意外的副作用。 DefaultContractResolver不存在这样的问题,因此在需要任何自定义套管逻辑时使用它会更安全。

  • 使用或DefaultContractResolver ,您可能希望缓存合同解析程序以获得最佳性能,因为它不会在每种类型的所有实例中全局共享合同信息。

  • 我不知道为什么Json.NET的骆驼案例解析器被设计为覆盖指定的名称,这可能是出于历史原因。

  • 命名策略最初是在Json.NET 9.0.1中引入的,所以这个答案仅适用于该版本以及之后的版本。

使用ContractResolver时,JsonProperty属性不受尊重。

您可以采取的措施来覆盖ContractResolver:

 public class MyResolver : CamelCasePropertyNamesContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if(member.GetCustomAttribute() is JsonPropertyAttribute jsonProperty) { property.PropertyName = jsonProperty.PropertyName; } return property; } } 

并使用你的解析器:

 var output2 = JsonConvert.SerializeObject(foo, new JsonSerializerSettings { ContractResolver = new MyResolver() });