研究员, 我在Newtonsoft.Json中遇到过一个奇怪的行为。
当我尝试序列化一个看起来像这样的对象时:
public class DMSDocWorkflowI
{
[JsonProperty("DMSDocWorkflowIResult")]
public bool DMSDocWorkflowIResult { get; set; }
[JsonProperty("DMSDocWorkflowIResultSpecified")]
public bool DMSDocWorkflowIResultSpecified { get; set; }
}
使用这个简单的调用,没有自定义的转换器/绑定器/合约解析器:
var testObject = new DMSDocWorkflowI();
var json = JsonConvert.SerializeObject(testObject, Formatting.Indented);
或甚至JToken.FromObject(...)
我总是只获得一个属性:
{
"DMSDocWorkflowIResultSpecified": false
}
当我附加跟踪编写器时,它只捕获这个:
[0]: "2016-08-30T11:06:27.779 Info Started serializing *****DMSDocWorkflowI. Path ''."
[1]: "2016-08-30T11:06:27.779 Verbose IsSpecified result for property 'DMSDocWorkflowIResult' on *****DMSDocWorkflowI: False. Path ''."
[2]: "2016-08-30T11:06:27.779 Info Finished serializing *****.DMSDocWorkflowI. Path ''."
[3]: "2016-08-30T11:06:27.780 Verbose Serialized JSON: \r\n{\r\n \"DMSDocWorkflowIResultSpecified\": false\r\n}"
所以似乎Newtonsoft.Json对待这个" Specified"财产有些神奇。 我能把它关掉吗? 我在生成的JSON中需要这两个属性,并且具有这些名称。
答案 0 :(得分:10)
在Json.NET 4.0.1 release notes:新功能中添加了XmlSerializer样式指定的属性支持,提及了非常这一行为。 XmlSerializer
功能依次在MinOccurs Attribute Binding Support中描述:
[对于可选字段] Xsd.exe生成类型为
bool
的公共字段,其名称为附加了Specified的元素字段名称。例如,如果元素字段的名称是startDate,则bool
字段的名称将变为startDateSpecified。将对象序列化为XML时,XmlSerializer类会检查bool
字段的值以确定是否编写该元素。
我觉得这个功能应该记录在here,但事实并非如此。您可能希望使用Newtonsoft open a documentation issue。
由于您不想要此行为,如果您使用的是Json.NET 11.0.1 or later,则可以通过实例化自己的DefaultContractResolver
并设置DefaultContractResolver.IgnoreIsSpecifiedMembers = true
来禁用所有类:
public static class JsonContractResolvers
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
public static readonly DefaultContractResolver IgnoreIsSpecifiedMembersResolver =
new DefaultContractResolver { IgnoreIsSpecifiedMembers = true };
}
然后将其传递给JsonConvert
,如下所示:
var settings = new JsonSerializerSettings { ContractResolver = JsonContractResolvers.IgnoreIsSpecifiedMembersResolver };
var json = JsonConvert.SerializeObject(testObject, Formatting.Indented, settings);
或创建JToken
执行:
var jToken = JToken.FromObject(testObject, JsonSerializer.CreateDefault(settings));
如果您使用的是早期版本,则需要创建并缓存custom contract resolver:
public static class JsonContractResolvers
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
public static readonly DefaultContractResolver IgnoreIsSpecifiedMembersResolver =
new IgnoreSpecifiedContractResolver();
}
internal class IgnoreSpecifiedContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.GetIsSpecified = null;
property.SetIsSpecified = null;
return property;
}
}