Решението:
Ще ви трябва персонализиран 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
проверката проверява за поле, което би идентифицирало типа подклас. По този начин 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 атрибути, в противен случай десериализацията ще постави стойностите по подразбиране на нула. Имате неизменен клас с внедрен интерфейс.
Някои ключови точки:
[JsonProperty]
трябва да присъства във всяко свойство, в противен случай свойствата ще се четат като нулеви;
[public SubClass1() { }]
трябва да присъства празен конструктор, за да могат конверторите да декларират празен клас.
- `[JsonConstructor] ' трябва да бъде маркиран в конструктора, който позволява на свойствата да получават стойности, предавани им в неизменните обекти.
{ get; }
трябва да се промени на { get; private set; }
, в противен случай всички свойства ще бъдат зададени на нула
public ISubClass1 SomeInterface { get; private set;}
в изпълнението трябва да се маркира с атрибут [JsonConverter(typeof(SubClass1Converter))]
.
Подклас:
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);
Препратки:
person
Middle
schedule
01.07.2020
JsonConstructor
имена на параметри на конструктор. - person dbc   schedule 02.07.2020