如何反序列化包含具有相同父类的不同类类型的对象的JSON数组

问题描述

我有两个具有相同父类的类,如下所示:

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属性不会丢失?

  1. 下面的方法将不起作用,因为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

JsonSubTypes

,

如果您的目标是仅使用不同的值类型反序列化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);进行反序列化。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...