Решение:
Вам понадобится собственный преобразователь 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
для правильной десериализации. Ссылка: Пуленепробиваемая десериализация
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; }
, иначе все свойства будут установлены на null
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