我正在尝试使用JSON.NET反序列化复杂的JSON结构:
{
"a": 1,
"b": "value",
"c": {
"d": "hello"
}
}
我需要将值转换器应用于c
属性。
我正在使用合同解析器,如下所示:
public class CustomPropertyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null && pi.GetCustomAttribute(typeof(MyCustomAttribute), true) != null)
{
prop.ValueProvider = new MyStringValueProvider(pi);
}
}
return props;
}
如果需要应用值提供程序的属性位于顶层(如b
),则此方法有效,但它不适用于嵌套值(d
)。根本没有为嵌套对象调用CreateProperties
。
如何确保合同解析器也适用于嵌套对象?
编辑:这是一个完整的最小复制品,应该打印“你好”和“世界”,但打印“olleh”和“dlrow”代替:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace JsonNetStackOverflow
{
public class Program
{
public static void Main(string[] args)
{
string json = "{'a':'olleh', 'b': { 'c': 'dlrow' } }";
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ContractResolver = new ReversePropertyResolver()
};
ClassA result = JsonConvert.DeserializeObject<ClassA>(json, settings);
Console.WriteLine(result.A);
Console.WriteLine(result.B.C);
Console.ReadLine();
}
}
public class ReverseAttribute : Attribute
{ }
public class ReversePropertyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in props.Where(p => p.PropertyType == typeof(string)))
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null && pi.GetCustomAttribute(typeof(ReverseAttribute), true) != null)
{
prop.ValueProvider = new ReverseValueProvider(pi);
}
}
return props;
}
}
public class ReverseValueProvider : IValueProvider
{
private readonly PropertyInfo targetProperty;
public ReverseValueProvider(PropertyInfo targetProperty)
{
this.targetProperty = targetProperty;
}
public object GetValue(object target)
{
string value = (string)targetProperty.GetValue(target);
return new string(value.Reverse().ToArray());
}
public void SetValue(object target, object value)
{
targetProperty.SetValue(target, new string(((string)value).Reverse().ToArray()));
}
}
public class ClassA
{
public ClassA(string a, ClassB b)
{
this.A = a;
this.B = b;
}
[Reverse]
[JsonProperty("a")]
public string A { get; set; }
[JsonProperty("b")]
public ClassB B { get; set; }
}
public class ClassB
{
public ClassB(string c)
{
this.C = c;
}
[Reverse]
[JsonProperty("c")]
public string C { get; set; }
}
}
答案 0 :(得分:1)
未调用ReverseValueProvider.SetValue()
方法的原因是您的类型ClassA
和ClassB
正在使用参数化构造函数构造,并且传入的值是您想要的值反向:
public class ClassB
{
public ClassB(string c)
{
// You would like c to be reversed but it's not since it's never set via its setter.
this.C = c;
}
[Reverse]
[JsonProperty("c")]
public string C { get; set; }
}
因为Json.NET通过构造函数填充这些值,所以它永远不会调用相应的属性setter,并且字符串永远不会被反转。
为确保调用setter(因此字符串被反转),您可以向类型添加私有无参数构造函数,并使用[JsonConstructor]
标记它们:
public class ClassA
{
[JsonConstructor]
ClassA() {}
public ClassA(string a, ClassB b)
{
this.A = a;
this.B = b;
}
[Reverse]
[JsonProperty("a")]
public string A { get; set; }
[JsonProperty("b")]
public ClassB B { get; set; }
}
public class ClassB
{
[JsonConstructor]
ClassB() { }
public ClassB(string c)
{
this.C = c;
}
[Reverse]
[JsonProperty("c")]
public string C { get; set; }
}