[英]Newtonsoft JsonConvert.SerializeObject ignoring JsonProperty if name is uppercase
I want to be able to use the CamelCasePropertyNameContractResolver
but override it for specific property names. 我希望能够使用
CamelCasePropertyNameContractResolver
但将其替换为特定的属性名称。 For this, I use the JsonProperty
attribute. 为此,我使用了
JsonProperty
属性。 This works fine except when the name that I choose is fully uppercase. 除非我选择的名称全为大写,否则此方法工作正常。 Any ideas what's wrong or how to get around it?
任何想法出什么问题或如何解决?
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. 在下面的示例中,当我不使用CamelCasePropertyNameContractResolver时,
Bar
被序列化为"BAR"
,但是当我使用解析器时, Bar
被序列化为"bar"
。 Foo
and CamelCaseProperty
are serialized correctly in both scenarios. 在两种情况下,
Foo
和CamelCaseProperty
均已正确序列化。
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; }
}
}
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 : 您看到它的原因是
CamelCasePropertyNamesContractResolver
是有意设计的,以覆盖字典键的大小写并显式设置属性名称 ,如从参考源中可以看到的:
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. 如果您不希望这样做,则可以使用多个选项来防止在不创建自己的自定义合同解析器类型的情况下使用显式名称。
Firstly , you could serialize using a DefaultContractResolver
with NamingStrategy = new CamelCaseNamingStrategy()
: 首先 ,您可以使用
DefaultContractResolver
进行序列化,并带有NamingStrategy = new CamelCaseNamingStrategy()
:
var settings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }
};
var output2 = JsonConvert.SerializeObject(foo, settings);
This leaves CamelCaseNamingStrategy.OverrideSpecifiedNames
at its default value of false
. 这将
CamelCaseNamingStrategy.OverrideSpecifiedNames
为其默认值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: 其次 ,如果您无权访问框架的合同解析器,则可以在特定属性上设置
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; }
}
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(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; }
}
Notes: 笔记:
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
. 尽管也可以修改
CamelCasePropertyNamesContractResolver
实例的NamingStrategy
,但是由于后者在每种类型的所有实例之间全局共享合同信息 ,如果您的应用程序尝试使用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. 使用
DefaultContractResolver
或对其进行子类化时,您可能希望缓存合同解析器以获得最佳性能,因为它不会在每种类型的所有实例之间全局共享合同信息。
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的驼峰式案例解析器旨在重写指定的名称,这可能是出于历史原因。
Naming strategies were first introduced in Json.NET 9.0.1 so this answer works only for that version and later. 命名策略最初是在Json.NET 9.0.1中引入的,因此此答案仅适用于该版本及更高版本。
JsonProperty Attribute is not honoured when you use a ContractResolver. 使用ContractResolver时,不支持JsonProperty属性。
What you can do to solve this issue is override the ContractResolver: 您可以解决此问题的方法是重写ContractResolver:
public class MyResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if(member.GetCustomAttribute<JsonPropertyAttribute>() is JsonPropertyAttribute jsonProperty)
{
property.PropertyName = jsonProperty.PropertyName;
}
return property;
}
}
And use your Resolver: 并使用您的解析器:
var output2 = JsonConvert.SerializeObject(foo, new JsonSerializerSettings { ContractResolver = new MyResolver() });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.