我正在尝试使用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
根本不被列为嵌套对象。
如何确保合同解析器也将其应用于嵌套对象?
编辑:这是一个完整的最小复制,应该打印" Hello"one_answers" World",但要打印" Olleh"one_answers" 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; }
}
}
您的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正在通过构造函数填充这些值,所以它从不调用相应的属性设置器,并且字符串永远不会相反。
要确保调用设置器(因此扭转字符串),您可以在类型的类型中添加私有参数的构造函数,并用[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; }
}