JSON.net:如何反序列化,而不使用默认的构造函数?
我有一个类,有一个默认的构造函数,也是一个重载的构造函数,接受一组参数。 这些参数与对象上的字段相匹配,并在构造上分配。 在这一点上,我需要其他用途的默认构造函数,所以我想保持它,如果我可以。
我的问题:如果我删除默认的构造函数并传入JSONstring,对象正确反序列化并传入构造函数参数没有任何问题。 我最终以我期望的方式回收对象。 但是,只要我将默认构造函数添加到对象中,当我调用JsonConvert.DeserializeObject<Result>(jsontext)
属性不再填充。
在这一点上,我尝试添加new JsonSerializerSettings(){CheckAdditionalContent = true}
到反序列化调用。 那什么都没做
另一个说明。 构造器参数确实匹配字段的名称,只是参数以小写字母开头。 我不认为这是重要的,因为像我所说的,反序列化工作正常,没有默认的构造函数。
这里是我的构造函数的示例:
public Result() { } public Result(int? code, string format, Dictionary<string, string> details = null) { Code = code ?? ERROR_CODE; Format = format; if (details == null) Details = new Dictionary<string, string>(); else Details = details; }
Json.Net更喜欢在对象上使用默认(无参数)构造函数。 如果有多个构造函数,并且您希望Json.Net使用非默认构造函数,那么您可以将[JsonConstructor]
属性添加到您希望Json.Net调用的构造函数中。
[JsonConstructor] public Result(int? code, string format, Dictionary<string, string> details = null) { ... }
构造函数参数名称与JSON对象的相应属性名称匹配以使其正确工作是非常重要的。 但是,您不一定必须为对象的每个属性都有一个构造函数参数。 对于那些没有被构造函数参数覆盖的JSON对象属性,Json.Net会尝试使用公共属性访问器(或者用[JsonProperty]
标记的属性/字段)来构造对象。
如果您不想为您的类添加属性,或者不想为要尝试反序列化的类控制源代码,那么另一种方法是创build一个自定义JsonConverter来实例化和填充对象。 例如:
class ResultConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(Result)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // Load the JSON for the Result into a JObject JObject jo = JObject.Load(reader); // Read the properties which will be used as constructor parameters int? code = (int?)jo["Code"]; string format = (string)jo["Format"]; // Construct the Result object using the non-default constructor Result result = new Result(code, format); // (If anything else needs to be populated on the result object, do that here) // Return the result return result; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
然后,将转换器添加到串行器设置中,并在反序列化时使用这些设置:
JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new ResultConverter()); Result result = JsonConvert.DeserializeObject<Result>(jsontext, settings);
有点晚了,不完全适合在这里,但我要在这里添加我的解决scheme,因为我的问题已经被closures,作为这一个副本,因为这个解决scheme是完全不同的。
我需要一个通用的方法来指示Json.NET
更喜欢用户定义的结构types的最具体的构造函数,所以我可以省略JsonConstructor
属性,它将添加一个依赖项到每个这样的结构定义的项目。
我已经反向工程了一下,并实现了一个自定义合约parsing器,我已经重写了CreateObjectContract
方法来添加我的自定义创build逻辑。
public class CustomContractResolver : DefaultContractResolver { protected override JsonObjectContract CreateObjectContract(Type objectType) { var c = base.CreateObjectContract(objectType); if (!IsCustomStruct(objectType)) return c; IList<ConstructorInfo> list = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).OrderBy(e => e.GetParameters().Length).ToList(); var mostSpecific = list.LastOrDefault(); if (mostSpecific != null) { c.OverrideCreator = CreateParameterizedConstructor(mostSpecific); c.CreatorParameters.AddRange(CreateConstructorParameters(mostSpecific, c.Properties)); } return c; } protected virtual bool IsCustomStruct(Type objectType) { return objectType.IsValueType && !objectType.IsPrimitive && !objectType.IsEnum && !objectType.Namespace.IsNullOrEmpty() && !objectType.Namespace.StartsWith("System."); } private ObjectConstructor<object> CreateParameterizedConstructor(MethodBase method) { method.ThrowIfNull("method"); var c = method as ConstructorInfo; if (c != null) return a => c.Invoke(a); return a => method.Invoke(null, a); } }
我正在使用它。
public struct Test { public readonly int A; public readonly string B; public Test(int a, string b) { A = a; B = b; } } var json = JsonConvert.SerializeObject(new Test(1, "Test"), new JsonSerializerSettings { ContractResolver = new CustomContractResolver() }); var t = JsonConvert.DeserializeObject<Test>(json); tAShouldEqual(1); tBShouldEqual("Test");