使用 json.net 在构造函数中使用接口参数反序列化不可变 类
Deserialize immutable classes with interface parameter in the constructor using json.net
我想用 Json.net 创建一些不可变的 classes,但遇到错误消息:“无法创建 SolutionName.InterfaceClassName.Type 类型的实例是接口或抽象 class 且无法实例化。
问题:
我有一个不可变的 class,实现了一些接口。
public interface ISubClass1
{
int number { get; }
string string1 { get; }
}
子class:
public class SubClass1 : ISubClass1
{
public int number { get; }
public string string1 { get; }
public SubClass1(int a, string str1)
{
number = a;
string1 = str1;
}
}
public class SubClass2 : ISubClass1
{
public int number { get; }
public string string1 { get; }
public string string2 { get; }
public SubClass2(int a, string str1, string str2)
{
number = a;
string1 = str1;
string2 = str2;
}
}
实施:
class Class1
{
public int SomeInt{ get; }
public ISubClass1 SomeInterface { get; }
public Class1(int a, ISubClass1 subclass)
{
SomeInt= a;
SomeInterface = subclass;
}
}
我可以序列化这个对象,一切正常。但是在反序列化的时候会报错
"Could not create an instance of type SolutionName.InterfaceClassName.Type is an interface or abstract class and cannot be instantiated"
这是由于ISubClass1 subclass
无法被Json.net识别。
解决方法:
您将需要自定义 Json 转换器,以便您可以使用所需的具体类型解析 ISubclass1
。
1 - 将此通用转换器添加到您的解决方案中。
public abstract class JsonCreationConverter<T> : JsonConverter
{
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">
/// contents of JSON object that will be deserialized
/// </param>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite
{
get { return false; }
}
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
2 - 然后像下面的例子一样继承任何你想翻译的接口。请注意,FieldExists
检查正在检查一个字段,该字段将标识 subclass 的类型。这样 Json 不需要 $type
信息即可正确反序列化。
参考:BulletProof Deserialization
public class SubClass1Converter : JsonCreationConverter<ISubClass1>
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new InvalidOperationException("Use default serialization.");
}
protected override ISubClass1 Create(Type objectType, JObject jObject)
{
if (FieldExists("string2", jObject))
{
return new SubClass2();
}
else
{
return new SubClass1();
}
}
private bool FieldExists(string fieldName, JObject jObject)
{
return jObject[fieldName] != null;
}
}
3 - 您已使用 Json.net 属性修改子classes 和实现,否则反序列化会将默认值设置为 null。你有一个不可变的 class 并实现了一些接口。
一些关键点:
[JsonProperty]
需要出现在每个 属性 上,否则属性将被读取为 null;
[public SubClass1() { }]
需要存在一个空的构造函数,以便转换器声明一个空的 class。
- `[JsonConstructor] ' 需要在构造函数上标记,允许属性在不可变对象中获取传递给它们的值。
{ get; }
需要更改为 { get; private set; }
否则所有属性都将设置为 null
public ISubClass1 SomeInterface { get; private set;}
在实现中需要标注[JsonConverter(typeof(SubClass1Converter))]
属性。
亚class:
public class SubClass1 : ISubClass1
{
[JsonProperty]
public int number { get; private set;}
[JsonProperty]
public string string1 { get; private set;}
public SubClass1() { }
[JsonConstructor]
public SubClass1(int a, string str1)
{
number = a;
string1 = str1;
}
}
public class SubClass2 : ISubClass1
{
[JsonProperty]
public int number { get; private set;}
[JsonProperty]
public string string1 { get; private set;}
[JsonProperty]
public string string2 { get; private set;}
public SubClass2() { }
[JsonConstructor]
public SubClass2(int a, string str1, string str2)
{
number = a;
string1 = str1;
string2 = str2;
}
}
实施:
class Class1
{
[JsonProperty]
public int SomeInt{ get; private set;}
[JsonProperty]
[JsonConverter(typeof(SubClass1Converter))]
public ISubClass1 SomeInterface { get; private set;}
[JsonConstructor]
public Class1(int a, ISubClass1 subclass)
{
SomeInt= a;
SomeInterface = subclass;
}
}
用法:
JsonSerializerSettings jsonSettings = new JsonSerializerSettings();
jsonSettings.Formatting = Formatting.Indented;
jsonSettings.Converters.Add(new SubClass1Converter()); //Optional
jsonSettings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor; //Optional
string jsonStr = JsonConvert.SerializeObject(cls1, jsonSettings);
Class1 deserializedObject = JsonConvert.DeserializeObject<Class1>(jsonStr , jsonSettings);
参考文献:
- Casting interfaces for deserialization in JSON.NET
我想用 Json.net 创建一些不可变的 classes,但遇到错误消息:“无法创建 SolutionName.InterfaceClassName.Type 类型的实例是接口或抽象 class 且无法实例化。
问题:
我有一个不可变的 class,实现了一些接口。
public interface ISubClass1
{
int number { get; }
string string1 { get; }
}
子class:
public class SubClass1 : ISubClass1
{
public int number { get; }
public string string1 { get; }
public SubClass1(int a, string str1)
{
number = a;
string1 = str1;
}
}
public class SubClass2 : ISubClass1
{
public int number { get; }
public string string1 { get; }
public string string2 { get; }
public SubClass2(int a, string str1, string str2)
{
number = a;
string1 = str1;
string2 = str2;
}
}
实施:
class Class1
{
public int SomeInt{ get; }
public ISubClass1 SomeInterface { get; }
public Class1(int a, ISubClass1 subclass)
{
SomeInt= a;
SomeInterface = subclass;
}
}
我可以序列化这个对象,一切正常。但是在反序列化的时候会报错
"Could not create an instance of type SolutionName.InterfaceClassName.Type is an interface or abstract class and cannot be instantiated"
这是由于ISubClass1 subclass
无法被Json.net识别。
解决方法:
您将需要自定义 Json 转换器,以便您可以使用所需的具体类型解析 ISubclass1
。
1 - 将此通用转换器添加到您的解决方案中。
public abstract class JsonCreationConverter<T> : JsonConverter
{
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">
/// contents of JSON object that will be deserialized
/// </param>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite
{
get { return false; }
}
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
2 - 然后像下面的例子一样继承任何你想翻译的接口。请注意,FieldExists
检查正在检查一个字段,该字段将标识 subclass 的类型。这样 Json 不需要 $type
信息即可正确反序列化。
参考:BulletProof Deserialization
public class SubClass1Converter : JsonCreationConverter<ISubClass1>
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new InvalidOperationException("Use default serialization.");
}
protected override ISubClass1 Create(Type objectType, JObject jObject)
{
if (FieldExists("string2", jObject))
{
return new SubClass2();
}
else
{
return new SubClass1();
}
}
private bool FieldExists(string fieldName, JObject jObject)
{
return jObject[fieldName] != null;
}
}
3 - 您已使用 Json.net 属性修改子classes 和实现,否则反序列化会将默认值设置为 null。你有一个不可变的 class 并实现了一些接口。
一些关键点:
[JsonProperty]
需要出现在每个 属性 上,否则属性将被读取为 null;[public SubClass1() { }]
需要存在一个空的构造函数,以便转换器声明一个空的 class。- `[JsonConstructor] ' 需要在构造函数上标记,允许属性在不可变对象中获取传递给它们的值。
{ get; }
需要更改为{ get; private set; }
否则所有属性都将设置为 nullpublic ISubClass1 SomeInterface { get; private set;}
在实现中需要标注[JsonConverter(typeof(SubClass1Converter))]
属性。
亚class:
public class SubClass1 : ISubClass1
{
[JsonProperty]
public int number { get; private set;}
[JsonProperty]
public string string1 { get; private set;}
public SubClass1() { }
[JsonConstructor]
public SubClass1(int a, string str1)
{
number = a;
string1 = str1;
}
}
public class SubClass2 : ISubClass1
{
[JsonProperty]
public int number { get; private set;}
[JsonProperty]
public string string1 { get; private set;}
[JsonProperty]
public string string2 { get; private set;}
public SubClass2() { }
[JsonConstructor]
public SubClass2(int a, string str1, string str2)
{
number = a;
string1 = str1;
string2 = str2;
}
}
实施:
class Class1
{
[JsonProperty]
public int SomeInt{ get; private set;}
[JsonProperty]
[JsonConverter(typeof(SubClass1Converter))]
public ISubClass1 SomeInterface { get; private set;}
[JsonConstructor]
public Class1(int a, ISubClass1 subclass)
{
SomeInt= a;
SomeInterface = subclass;
}
}
用法:
JsonSerializerSettings jsonSettings = new JsonSerializerSettings();
jsonSettings.Formatting = Formatting.Indented;
jsonSettings.Converters.Add(new SubClass1Converter()); //Optional
jsonSettings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor; //Optional
string jsonStr = JsonConvert.SerializeObject(cls1, jsonSettings);
Class1 deserializedObject = JsonConvert.DeserializeObject<Class1>(jsonStr , jsonSettings);
参考文献:
- Casting interfaces for deserialization in JSON.NET