我有一堆我无法控制的类,它们是在可空类型之前创建的。这些类中使用的约定如下:
Id
IdSpecified = false
换句话说,对于名为“Abc”的给定非可空属性,有一个名为“AbcSpecified”的单独布尔属性,它指示第一个属性是否具有值。
有没有办法将非可空属性视为可空,并在序列化和反序列化期间排除以Specified
结尾的所有属性?我希望我能够做到这一点,因为有超过100个这样的类。
答案 0 :(得分:0)
我能够使用自定义IContractResolver
和IValueProvider
为此设置通用解决方案。合同解析器负责识别属性对" Xyz"和" XyzSpecified"在每个班级(我分别称这些"目标"和"指示符"属性),并确保每对都确保指标属性被排除,同时还附加一个值提供程序实例到目标属性。反过来,值提供程序处理为每个对象实例读取或写入的内容的决定。在序列化时,如果指标属性设置为true,它只会写出目标属性。相反,在反序列化时,它根据JSON中是否存在值来设置指标属性,但只有在存在值时才设置对象的目标属性。
以下是自定义解析程序和值提供程序的代码:
> fmt = re.split(r'\[(-?[0-9.]+,\s?-?[0-9.]+).\s*\d\s*(\d{4}-\d{1,2}-\d{1,2}\s+\d{2}:\d{2}:\d{2})',example)
> fmt # watch what happens when I change the grouping.
['', '27.994195699999999, -82.569434900000005', '2011-08-28 19:02:36', ' text text text text']
> location = literal_eval('(' + fmt[1] + ')')
> time = fmt[2]
> text = fmt[3]
要使用解析程序,请创建一个新的public class CustomResolver : DefaultContractResolver
{
const string IndicatorKeyword = "Specified";
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
Dictionary<string, JsonProperty> dict = props.ToDictionary(p => p.UnderlyingName);
foreach (JsonProperty prop in props)
{
string name = prop.UnderlyingName;
if (name.Length > IndicatorKeyword.Length && name.EndsWith(IndicatorKeyword))
{
// We have an indicator property; ignore it for serialization purposes
prop.Ignored = true;
// Find the corresponding target property, e.g. "XyzSpecified" => "Xyz"
string targetName = name.Substring(0, name.Length - IndicatorKeyword.Length);
JsonProperty coProp = null;
if (dict.TryGetValue(targetName, out coProp))
{
// Create a value provider for the property pointing to the
// "real" target and indicator properties from the containing type
PropertyInfo realTarget = type.GetProperty(targetName);
PropertyInfo realIndicator = type.GetProperty(name);
coProp.ValueProvider = new CustomValueProvider(realTarget, realIndicator);
}
}
}
return props;
}
class CustomValueProvider : IValueProvider
{
PropertyInfo targetProperty;
PropertyInfo indicatorProperty;
public CustomValueProvider(PropertyInfo targetProperty, PropertyInfo indicatorProperty)
{
this.targetProperty = targetProperty;
this.indicatorProperty = indicatorProperty;
}
// GetValue is called by Json.Net during serialization.
// The target parameter has the object from which to read the value;
// the return value is what gets written to the JSON
public object GetValue(object target)
{
bool isSpecified = (bool)indicatorProperty.GetValue(target);
return isSpecified ? targetProperty.GetValue(target) : null;
}
// SetValue gets called by Json.Net during deserialization.
// The value parameter has the value read from the JSON;
// target is the object on which to set the value.
public void SetValue(object target, object value)
{
bool isSpecified = value != null;
indicatorProperty.SetValue(target, isSpecified);
if (isSpecified) targetProperty.SetValue(target, value);
}
}
}
实例,然后将JsonSerializerSettings
属性设置为解析程序的新实例。将设置传递给ContractResolver
或JsonConvert.SerializeObject()
方法,一切正常。
这是一个完整的往返演示:https://dotnetfiddle.net/i39c8d