问题描述
我有两个具有相同父类的类,如下所示:
class ListaAlimentarPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _prefs = new PreferenciasUsuario();
final alimentarBloc = Provider.alimentarBloc(context);
alimentarBloc.cargarAlimentar(_prefs.idEmpresa,_prefs.idEstanque);
return SafeArea(
child: Scaffold(
body: _crearListado(context,alimentarBloc),bottomNavigationBar: utils.crearBottom(context,2),),);
}
Widget _crearListado(BuildContext context,AlimentarBloc alimentarBloc) {
return StreamBuilder(
stream: alimentarBloc.alimentarStream,builder: (BuildContext context,AsyncSnapshot<List<AlimentarModel>> snapshot){
if (snapshot.hasData) {
final alimentarList = snapshot.data;
alimentarList.sort((a,b) => b.fecha.compareTo(a.fecha));
return Container(
child: Stack(
children: <Widget>[
ListView.builder(
itemCount: alimentarList.length,itemBuilder: (context,i) =>_crearItem(context,alimentarBloc,alimentarList[i]),],);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center (child: Image(image: AssetImage('assets/preloader.gif'),height: 200.0,));
},);
}
Widget _crearItem(BuildContext context,AlimentarBloc alimentarBloc,AlimentarModel alimentar) {
return Stack(
alignment: Alignment.centerLeft,children: <Widget>[
Container(
width: double.infinity,child: Card(
child: ListTile(
title: Text('${alimentar.nombreAlimentoFull}'),onTap: () => null,)
),);
}
}
现在,我有一个API,该API返回的数组类型为JSON字符串,其中包含类型为ChildInteger,ChildDateTime的对象。
JSON字符串:
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
}
public class ChildInteger : Parent
{
public int Value { get; set; } = 0;
}
public class ChildDateTime : Parent
{
public DateTime Value { get; set; } = DateTime.MinValue;
}
如何反序列化为正确的类型,以使value属性不会丢失?
-
下面的方法将不起作用,因为value属性丢失了。
List parentList1 = new List(); parentList1 = JsonConvert.DeserializeObject (json);
注意:这些类来自第三方API。因此需要在不修改类的情况下实现它。
解决方法
为什么不尝试这样的事情?
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
}
public class ChildInteger : Parent
{
public int Value { get; set; } = 0;
}
public class ChildDateTime : Parent
{
public DateTime Value { get; set; } = DateTime.MinValue;
}
public static void Main()
{
var json = "[{\"Value\":1,\"Name\":\"Child Integer 1\",\"Type\":\"Integer\"},{\"Value\":\"2020-08-31T08:29:11.9002559+05:30\",\"Name\":\"Child DateTime 1\",\"Type\":\"DateTime\"}]";
List<Parent> jarray = JArray.Parse(json).AsEnumerable().Select<JToken,Parent>(x => {
switch(x["Type"].ToObject<string>())
{
case "Integer":
return x.ToObject<ChildInteger>();
case "DateTime":
return x.ToObject<ChildDateTime>();
}
return null;
}).ToList();
Console.WriteLine(jarray.Count()); // prints 2
foreach(var p in jarray) {
Console.WriteLine(p.GetType().GetProperty("Value",BindingFlags.Instance | BindingFlags.Public).GetValue(p));
}
// prints
// 1
// 08/31/2020 02:59:11
}
注意:我必须为列表中缺少的子类型添加继承,并将Date
的{{1}}属性更改为Value
。
有许多解决方案。假设您不需要显式转换器,并且需要离散类型,不想使用对象或动态对象,则可以使用doc。应该注意的是,这将更适用于更复杂的模式。但是,添加胡椒粉和盐调味
给予
[JsonConverter(typeof(JsonSubtypes),"type")]
[JsonSubtypes.KnownSubType(typeof(ChildInteger),"Integer")]
[JsonSubtypes.KnownSubType(typeof(ChildDateTime),"DateTime")]
public abstract class Child
{
[JsonProperty("type")]
public virtual string Type { get; }
public string Name { get; set; }
public abstract string GetValue();
}
public class ChildInteger : Child
{
public override string Type => "Integer";
public int Value { get; set; }
public override string GetValue()
=> Value.ToString();
}
public class ChildDateTime : Child
{
public override string Type => "DateTime";
public DateTime Value { get; set; }
public override string GetValue()
=> Value.ToString();
}
用法
var input = "[{\"Value\":1,\"Type\":\"DateTime\"}]";
var results = JsonConvert.DeserializeObject<List<Child>>(input);
foreach (var item in results)
Console.WriteLine($"{item.Name},{item.GetValue()}");
输出
Child Integer 1,1
Child DateTime 1,08/31/2020 02:59:11
,
如果您的目标是仅使用不同的值类型反序列化JSON,则可能更喜欢使用dynamic
属性。 参考: Using type dynamic。
public class Parent
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public dynamic Value { get; set; }
}
通常对var result = JsonConvert.DeserializeObject<List<Parent>>(json);
进行反序列化。