XSD.EXE + JSON.NET - 如何处理xxxSpecified生成的成员?
XSD.EXE + JSON.NET - How to deal with xxxSpecified generated members?
当使用 XSD.EXE 从 XML 架构生成 类 时,它会生成给定对象的任何基元的 xxxSpecified 成员:
<xs:complexType name ="Foo">
<xs:all>
<xs:element name ="Count" type = "xs:integer"/>
</xs:all>
</xs:complexType>
..生成:
public class Foo
{
public int Count { get; set; }
public bool CountSpecified { get; set; }
}
看来最新版本的JSON.NET可以在反序列化时自动设置这些属性。
string request = "{ Count : 10 }";
var object = JsonConvert.Deserialize<Foo>(request)
Assert.IsTrue(object.Count = 10); // Yup
Assert.IsTrue(object.CountSpecified == true); //Also yup - JSON.NET works!
然而,当采用其他方式时,xxxSpecified 属性包含在 JSON 输出中,这是不正确的,因为它不是模式的一部分。
string request = JsonConvert.Serialize(object);
//{
// Count: 10,
// CountSpecified : true <-- This is incorrect - should not be output
//}
我是否缺少控制是否输出 xxxSpecified 属性的设置?我怎样才能抑制它?
(注意:这是此处回答的问题的排列:
JSON.NET, XmlSerializer and "Specified" property
...但它涉及创建扩展 类,这对我来说是不可能的,因为架构中有数百个 类,而且我无法更改继承层次结构。所以答案是行不通的。寻找其他方式。)
您可以创建自己的合同解析器来过滤掉 xxxSpecified
属性:
public class SkipSpecifiedContractResolver : DefaultContractResolver
{
// 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."
static SkipSpecifiedContractResolver instance;
static SkipSpecifiedContractResolver() { instance = new SkipSpecifiedContractResolver(); }
public static SkipSpecifiedContractResolver Instance { get { return instance; } }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
ILookup<string, JsonProperty> lookup = null;
foreach (var property in properties)
{
if (property.GetIsSpecified != null && property.SetIsSpecified != null)
{
var name = property.UnderlyingName + "Specified";
lookup = lookup ?? properties.ToLookup(p => p.UnderlyingName);
var specified = lookup[name]
// Possibly also check for [XmlIgnore] being applied. While not shown in the question, xsd.exe will always
// apply [XmlIgnore] to xxxSpecified tracking properties.
//.Where(p => p.AttributeProvider.GetAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute),true).Any())
.SingleOrDefault();
if (specified != null)
specified.Ignored = true;
}
}
return properties;
}
}
然后像这样使用它:
var settings = new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
var object = JsonConvert.DeserializeObject<Foo>(request, settings);
如果你想一直这样做,你可以在全局设置合同解析器 JsonConvert.DefaultSettings
:
JsonConvert.DefaultSettings = (() =>
{
return new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
});
当使用 XSD.EXE 从 XML 架构生成 类 时,它会生成给定对象的任何基元的 xxxSpecified 成员:
<xs:complexType name ="Foo">
<xs:all>
<xs:element name ="Count" type = "xs:integer"/>
</xs:all>
</xs:complexType>
..生成:
public class Foo
{
public int Count { get; set; }
public bool CountSpecified { get; set; }
}
看来最新版本的JSON.NET可以在反序列化时自动设置这些属性。
string request = "{ Count : 10 }";
var object = JsonConvert.Deserialize<Foo>(request)
Assert.IsTrue(object.Count = 10); // Yup
Assert.IsTrue(object.CountSpecified == true); //Also yup - JSON.NET works!
然而,当采用其他方式时,xxxSpecified 属性包含在 JSON 输出中,这是不正确的,因为它不是模式的一部分。
string request = JsonConvert.Serialize(object);
//{
// Count: 10,
// CountSpecified : true <-- This is incorrect - should not be output
//}
我是否缺少控制是否输出 xxxSpecified 属性的设置?我怎样才能抑制它?
(注意:这是此处回答的问题的排列:
JSON.NET, XmlSerializer and "Specified" property
...但它涉及创建扩展 类,这对我来说是不可能的,因为架构中有数百个 类,而且我无法更改继承层次结构。所以答案是行不通的。寻找其他方式。)
您可以创建自己的合同解析器来过滤掉 xxxSpecified
属性:
public class SkipSpecifiedContractResolver : DefaultContractResolver
{
// 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."
static SkipSpecifiedContractResolver instance;
static SkipSpecifiedContractResolver() { instance = new SkipSpecifiedContractResolver(); }
public static SkipSpecifiedContractResolver Instance { get { return instance; } }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
ILookup<string, JsonProperty> lookup = null;
foreach (var property in properties)
{
if (property.GetIsSpecified != null && property.SetIsSpecified != null)
{
var name = property.UnderlyingName + "Specified";
lookup = lookup ?? properties.ToLookup(p => p.UnderlyingName);
var specified = lookup[name]
// Possibly also check for [XmlIgnore] being applied. While not shown in the question, xsd.exe will always
// apply [XmlIgnore] to xxxSpecified tracking properties.
//.Where(p => p.AttributeProvider.GetAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute),true).Any())
.SingleOrDefault();
if (specified != null)
specified.Ignored = true;
}
}
return properties;
}
}
然后像这样使用它:
var settings = new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
var object = JsonConvert.DeserializeObject<Foo>(request, settings);
如果你想一直这样做,你可以在全局设置合同解析器 JsonConvert.DefaultSettings
:
JsonConvert.DefaultSettings = (() =>
{
return new JsonSerializerSettings { ContractResolver = SkipSpecifiedContractResolver.Instance };
});