aoc*_*via 35 c# serialization json json.net
我试图将JSON字符串反序列化为具体类,该类继承自抽象类,但我无法使其工作.我用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);
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试转换生成的对象,它就不起作用.
我不使用DeserializeObject的原因是我有很多具体的类.
有什么建议?
mba*_*amo 55
有人可能不想使用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; }
}
Run Code Online (Sandbox Code Playgroud)
然后,基类的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
}
}
Run Code Online (Sandbox Code Playgroud)
而已.现在,您可以使用序列化/反序列化任何派生类.您还可以在其他类中使用基类,并对其进行序列化/反序列化,而无需任何额外的工作:
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);
Run Code Online (Sandbox Code Playgroud)
Gru*_*ndy 22
尝试这样的事情
public AbstractClass Decode(string jsonString)
{
var jss = new JavaScriptSerializer();
return jss.Deserialize<ConcreteClass>(jsonString);
}
Run Code Online (Sandbox Code Playgroud)
此方案的更新可以根据需要进行所有工作
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);
Run Code Online (Sandbox Code Playgroud)
其中,c类型是test.Base {test.Der}
UPDATE
@Gusman建议使用TypeNameHandling.Objects而不是TypeNameHandling.All.这就足够了,它会产生一个不那么详细的序列化.
Xav*_*rAM 19
事实上,因为它已经在更新,最简单的方法是说(2019年)是使用一个简单的自定义预先定义JsonSerializerSettings,为解释在这里
string jsonTypeNameAll = JsonConvert.SerializeObject(priceModels, Formatting.Indented,new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
Run Code Online (Sandbox Code Playgroud)
对于反序列化:
TDSPriceModels models = JsonConvert.DeserializeObject<TDSPriceModels>(File.ReadAllText(jsonPath), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
Run Code Online (Sandbox Code Playgroud)
小智 8
我建议以下列方式使用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<BaseClass>
{
private ClassDiscriminatorEnum _currentObjectType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jobj = JObject.ReadFrom(reader);
_currentObjectType = jobj["Type"].ToObject<ClassDiscriminatorEnum>();
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)