Возможно, вы не захотите использовать TypeNameHandling (потому что требуется более компактный json или хочет использовать определенное имя для переменной типа, отличной от «$ type»). Между тем, customerCreationConverter approach не будет работать, если вы хотите десериализовать базовый класс на любой из нескольких производных классов, не зная, какой из них следует использовать заранее.
Альтернативой является использование int или другого типа в базовом классе и определение JsonConverter.
[JsonConverter(typeof(BaseConverter))]
abstract class Base
{
public int ObjType { get; set; }
public int Id { get; set; }
}
class DerivedType1 : Base
{
public string Foo { get; set; }
}
class DerivedType2 : Base
{
public string Bar { get; set; }
}
JsonConverter для базового класса может затем десериализовать объект в зависимости от его типа. Усложнение состоит в том, что во избежание переполнения стека (когда JsonConverter повторно вызывает себя), во время этой десериализации должен использоваться пользовательский разрешитель.
public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
{
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (typeof(Base).IsAssignableFrom(objectType) && !objectType.IsAbstract)
return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow)
return base.ResolveContractConverter(objectType);
}
}
public class BaseConverter : JsonConverter
{
static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new BaseSpecifiedConcreteClassConverter() };
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Base));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
switch (jo["ObjType"].Value<int>())
{
case 1:
return JsonConvert.DeserializeObject<DerivedType1>(jo.ToString(), SpecifiedSubclassConversion);
case 2:
return JsonConvert.DeserializeObject<DerivedType2>(jo.ToString(), SpecifiedSubclassConversion);
default:
throw new Exception();
}
throw new NotImplementedException();
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException(); // won't be called because CanWrite returns false
}
}
Всё. Теперь вы можете использовать serialize/deserialize любой производный класс.Вы также можете использовать базовый класс в других классах и сериализации/десериализации тех, без каких-либо дополнительных работ:
class Holder
{
public List<Base> Objects { get; set; }
}
string json = @"
[
{
""Objects"" :
[
{ ""ObjType"": 1, ""Id"" : 1, ""Foo"" : ""One"" },
{ ""ObjType"": 1, ""Id"" : 2, ""Foo"" : ""Two"" },
]
},
{
""Objects"" :
[
{ ""ObjType"": 2, ""Id"" : 3, ""Bar"" : ""Three"" },
{ ""ObjType"": 2, ""Id"" : 4, ""Bar"" : ""Four"" },
]
},
]";
List<Holder> list = JsonConvert.DeserializeObject<List<Holder>>(json);
string serializedAgain = JsonConvert.SerializeObject(list);
Debug.WriteLine(serializedAgain);
для десериализации вам нужно создать экземпляр объекта, но вы не можете создать экземпляр абстрактного класса – Grundy
Я хочу, чтобы создать экземпляр конкретного класса , извините, если было не ясно – aochagavia
вы можете предоставить немного больше кода? – Grundy