使用 JSON.NET 在 C# 中的 class 中使用缺少默认构造函数反序列化 json
Deserialize json with missing default constructor in the class in C# using JSON.NET
我正在尝试将一个字符串 deserialize
转换为一个对象。问题是我想使用默认构造函数反序列化,但 class 中不存在。 class 只有一个带参数的构造函数。而且我不允许更改 class。我的场景是这样的:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class ConnectionSummary
{
public ConnectionSummary(Connection connection)
{
this.ConnectionId = connection.Id;
this.SystemId = connection.SystemId;
}
[JsonProperty(PropertyName = "connectionId", Required = Required.Always)]
public string ConnectionId { get; set; }
[JsonProperty(PropertyName = "systemId")]
public string SystemId { get; set; }
}
public class Connection
{
public Connection()
{
// Initialization of some properties
}
[JsonProperty(PropertyName = "systemId", Required = Required.Always)]
public string SystemId { get; set; }
[JsonProperty(PropertyName = "id", Required = Required.Always)]
public string Id { get; set; }
// Other properties
}
public class Program
{
public static void Main()
{
var json = "{\"connectionId\":\"id\",\"systemId\":\"sId\"}";
var deserial = JsonConvert.DeserializeObject<ConnectionSummary>(json); // getting error here.
Console.WriteLine(deserial.ToString());
}
}
堆栈跟踪:
Run-time exception (line 43): Exception has been thrown by the target of an invocation.
Stack Trace:
[System.NullReferenceException: Object reference not set to an instance of an object.]
at ConnectionSummary..ctor(Connection connection) :line 9
[System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.]
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Newtonsoft.Json.Utilities.LateBoundReflectionDelegateFactory.<>c__DisplayClass3_0.<CreateParameterizedConstructor>b__0(Object[] a)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at Program.Main() :line 43
我发现如果我在 ConnectionSummary
class 中添加一个 private
默认构造函数并在 JsonSerializerSettings
中添加 ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
可以解决问题但我不能那样做。我还能在这里做其他事情吗?
Fiddle Url
在这种情况下,您可以自己调用构造函数,并将实例提供给转换器:
var json = "{\"connectionId\":\"id\",\"systemId\":\"sId\"}";
var cs = new ConnectionSummary(new Connection());
Newtonsoft.Json.JsonConvert.PopulateObject(json, cs);
您可以通过为 ConnectionSummary
class 定制 JsonConverter
来解决这个问题,如下所示:
public class ConnectionSummaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ConnectionSummary);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Connection conn = new Connection
{
Id = (string)jo["connectionId"],
SystemId = (string)jo["systemId"]
};
return new ConnectionSummary(conn);
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后像这样反序列化:
var deserial = JsonConvert.DeserializeObject<ConnectionSummary>(json, new ConnectionSummaryConverter());
Fiddle: https://dotnetfiddle.net/U4UR3o
我正在尝试将一个字符串 deserialize
转换为一个对象。问题是我想使用默认构造函数反序列化,但 class 中不存在。 class 只有一个带参数的构造函数。而且我不允许更改 class。我的场景是这样的:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class ConnectionSummary
{
public ConnectionSummary(Connection connection)
{
this.ConnectionId = connection.Id;
this.SystemId = connection.SystemId;
}
[JsonProperty(PropertyName = "connectionId", Required = Required.Always)]
public string ConnectionId { get; set; }
[JsonProperty(PropertyName = "systemId")]
public string SystemId { get; set; }
}
public class Connection
{
public Connection()
{
// Initialization of some properties
}
[JsonProperty(PropertyName = "systemId", Required = Required.Always)]
public string SystemId { get; set; }
[JsonProperty(PropertyName = "id", Required = Required.Always)]
public string Id { get; set; }
// Other properties
}
public class Program
{
public static void Main()
{
var json = "{\"connectionId\":\"id\",\"systemId\":\"sId\"}";
var deserial = JsonConvert.DeserializeObject<ConnectionSummary>(json); // getting error here.
Console.WriteLine(deserial.ToString());
}
}
堆栈跟踪:
Run-time exception (line 43): Exception has been thrown by the target of an invocation.
Stack Trace:
[System.NullReferenceException: Object reference not set to an instance of an object.]
at ConnectionSummary..ctor(Connection connection) :line 9
[System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.]
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Newtonsoft.Json.Utilities.LateBoundReflectionDelegateFactory.<>c__DisplayClass3_0.<CreateParameterizedConstructor>b__0(Object[] a)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at Program.Main() :line 43
我发现如果我在 ConnectionSummary
class 中添加一个 private
默认构造函数并在 JsonSerializerSettings
中添加 ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
可以解决问题但我不能那样做。我还能在这里做其他事情吗?
Fiddle Url
在这种情况下,您可以自己调用构造函数,并将实例提供给转换器:
var json = "{\"connectionId\":\"id\",\"systemId\":\"sId\"}";
var cs = new ConnectionSummary(new Connection());
Newtonsoft.Json.JsonConvert.PopulateObject(json, cs);
您可以通过为 ConnectionSummary
class 定制 JsonConverter
来解决这个问题,如下所示:
public class ConnectionSummaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ConnectionSummary);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Connection conn = new Connection
{
Id = (string)jo["connectionId"],
SystemId = (string)jo["systemId"]
};
return new ConnectionSummary(conn);
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
然后像这样反序列化:
var deserial = JsonConvert.DeserializeObject<ConnectionSummary>(json, new ConnectionSummaryConverter());
Fiddle: https://dotnetfiddle.net/U4UR3o