我正在尝试使用 JSON.NET 反序列化复杂的 JSON 结构:
{
"a": 1,
"b": "value",
"c": {
"d": "hello"
}
}
我需要将值转换器应用到 c
属性。
我正在使用如下所示的契约(Contract)解析器:
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
根本不会为嵌套对象调用。
如何确保契约(Contract)解析器也应用于嵌套对象?
编辑:这是一个完整的最小重现,应该打印“hello”和“world”,但打印“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; }
}
}
最佳答案
未调用 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 被调用(因此字符串被反转),您可以将私有(private)无参数构造函数添加到您的类型中,并用 [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; }
}
关于c# - 解析的 JSON.NET 契约(Contract)不适用于内部对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40728650/