将JSON反序列化为抽象类

我试图将JSON字符串反序列化为具体类,该类inheritance自抽象类,但我无法使其工作。 我用Google搜索并尝试了一些解决方案,但它们似乎也没有用。

这就是我现在拥有的:

abstract class AbstractClass { } class ConcreteClass { } public AbstractClass Decode(string jsonString) { JsonSerializerSettings jss = new JsonSerializerSettings(); jss.TypeNameHandling = TypeNameHandling.All; return (AbstractClass)JsonConvert.DeserializeObject(jsonString, null, jss); } 

但是,如果我尝试转换生成的对象,它就不起作用。

我不使用DeserializeObject的原因是我有很多具体的类

有什么建议?

  • 我正在使用Newtonsoft.Json

尝试这样的事情

 public AbstractClass Decode(string jsonString) { var jss = new JavaScriptSerializer(); return jss.Deserialize(jsonString); } 

UPDATE
对于这种情况,可以根据需要进行所有工作

 public abstract class Base { public abstract int GetInt(); } public class Der:Base { int g = 5; public override int GetInt() { return g+2; } } public class Der2 : Base { int i = 10; public override int GetInt() { return i+17; } } .... var jset = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All }; Base b = new Der() string json = JsonConvert.SerializeObject(b, jset); .... Base c = (Base)JsonConvert.DeserializeObject(json, jset); 

其中c类型为test.Base {test.Der}

UPDATE

@Gusman建议使用TypeNameHandling.Objects而不是TypeNameHandling.All 。 这就足够了,它会产生一个不那么详细的序列化。

有人可能不想使用TypeNameHandling(因为需要更紧凑的json或者想要为“$ type”以外的类型变量使用特定名称)。 同时,如果想要将基类反序列化为多个派生类中的任何一个而不知道提前使用哪一个,那么customerCreationConverter方法将不起作用。

另一种方法是在基类中使用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()) { case 1: return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); case 2: return JsonConvert.DeserializeObject(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 } } 

而已。 现在,您可以使用序列化/反序列化任何派生类。 您还可以在其他类中使用基类,并对其进行序列化/反序列化,而无需任何额外的工作:

 class Holder { public List 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 list = JsonConvert.DeserializeObject>(json); string serializedAgain = JsonConvert.SerializeObject(list); Debug.WriteLine(serializedAgain); 

我建议以下列方式使用CustomCreationConverter:

 public enum ClassDiscriminatorEnum { ChildClass1, ChildClass2 } public abstract class BaseClass { public abstract ClassDiscriminatorEnum Type { get; } } public class Child1 : BaseClass { public override ClassDiscriminatorEnum Type => ClassDiscriminatorEnum.ChildClass1; public int ExtraProperty1 { get; set; } } public class Child2 : BaseClass { public override ClassDiscriminatorEnum Type => ClassDiscriminatorEnum.ChildClass2; } public class BaseClassConverter : CustomCreationConverter { private ClassDiscriminatorEnum _currentObjectType; public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jobj = JObject.ReadFrom(reader); _currentObjectType = jobj["Type"].ToObject(); return base.ReadJson(jobj.CreateReader(), objectType, existingValue, serializer); } public override BaseClass Create(Type objectType) { switch (_currentObjectType) { case ClassDiscriminatorEnum.ChildClass1: return new Child1(); case ClassDiscriminatorEnum.ChildClass2: return new Child2(); default: throw new NotImplementedException(); } } } 
  public class CustomConverter : JsonConverter { private static readonly JsonSerializer Serializer = new JsonSerializer(); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var typeString = jObject.Value("Kind"); //Kind is a property in json , from which we know type of child classes var requiredType = RecoverType(typeString); return Serializer.Deserialize(jObject.CreateReader(), requiredType); } private Type RecoverType(string typeString) { if (typeString.Equals(type of child class1, StringComparison.OrdinalIgnoreCase)) return typeof(childclass1); if (typeString.Equals(type of child class2, StringComparison.OrdinalIgnoreCase)) return typeof(childclass2); throw new ArgumentException("Unrecognized type"); } public override bool CanConvert(Type objectType) { return typeof(Base class).IsAssignableFrom(objectType) || typeof((Base class) == objectType; } public override bool CanWrite { get { return false; } } } 

现在将此转换器添加到JsonSerializerSettings中,如下所示

  var jsonSerializerSettings = new JsonSerializerSettings(); jsonSerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); jsonSerializerSettings.Converters.Add(new CustomConverter()); 

添加序列化或反序列化基类对象后,如下所示

  JsonConvert.DeserializeObject("json string", jsonSerializerSettings );