如何用C#派生类反序列化不同Web源的JSON数据?
解决JSON反序列化的抽象类继承优化方案
问题根源分析
栈溢出的核心原因是派生类中Value属性实现错误——未使用私有字段存储数据,而是在get/set逻辑中直接调用属性自身,触发无限递归。
正确的抽象类结构设计
抽象Data类及派生类
先实现支持字符串索引访问的抽象基类与具体数据类:
public abstract class Data { // 定义字符串索引器的抽象接口 public abstract object this[string key] { get; set; } } // 对应第一个数据源的具体数据类 public class Type1Data : Data { public string Campo1 { get; set; } public decimal Valor { get; set; } // 实现索引器,映射到具体字段 public override object this[string key] { get => key switch { nameof(Campo1) => Campo1, nameof(Valor) => Valor, _ => throw new KeyNotFoundException($"Key {key} not found in Type1Data") }; set { switch (key) { case nameof(Campo1): Campo1 = value as string; break; case nameof(Valor): Valor = Convert.ToDecimal(value); break; default: throw new KeyNotFoundException($"Key {key} not found in Type1Data"); } } } } // 对应第二个数据源的具体数据类 public class Type2Data : Data { public string IndiceNome { get; set; } public double Pontuacao { get; set; } // 实现索引器,映射到具体字段 public override object this[string key] { get => key switch { nameof(IndiceNome) => IndiceNome, nameof(Pontuacao) => Pontuacao, _ => throw new KeyNotFoundException($"Key {key} not found in Type2Data") }; set { switch (key) { case nameof(IndiceNome): IndiceNome = value as string; break; case nameof(Pontuacao): Pontuacao = Convert.ToDouble(value); break; default: throw new KeyNotFoundException($"Key {key} not found in Type2Data"); } } } }
抽象Root类及派生类(修复栈溢出)
通过私有字段存储数据,同时为反序列化提供具体类型绑定的属性:
using System.Text.Json.Serialization; public abstract class Root { [JsonPropertyName("@odata.context")] public string ODataContext { get; set; } public abstract List<Data> Value { get; set; } } // 泛型抽象基类,消除重复代码 public abstract class Root<T> : Root where T : Data { [JsonPropertyName("value")] public List<T> TypedValue { get; set; } public override List<Data> Value { get => TypedValue?.Cast<Data>().ToList() ?? new List<Data>(); set => TypedValue = value?.Cast<T>().ToList() ?? new List<T>(); } } // 各数据源的Root类只需继承泛型基类,无需重复实现逻辑 public class RootType1 : Root<Type1Data> { } public class RootType2 : Root<Type2Data> { }
反序列化示例(使用System.Text.Json)
// 模拟从Type1数据源获取的JSON string type1Json = @" { ""@odata.context"": ""https://example.com/odata/$metadata#Cambios"", ""value"": [ { ""Campo1"": ""USD"", ""Valor"": 5.25 }, { ""Campo1"": ""EUR"", ""Valor"": 5.6 } ] }"; // 反序列化为具体Root类 RootType1 root1 = JsonSerializer.Deserialize<RootType1>(type1Json); // 通过抽象Root类统一访问数据 foreach (Data item in root1.Value) { Console.WriteLine($"Moeda: {item["Campo1"]}, Cotação: {item["Valor"]}"); } // 模拟从Type2数据源获取的JSON string type2Json = @" { ""@odata.context"": ""https://example.com/odata/$metadata#Indices"", ""value"": [ { ""IndiceNome"": ""IBOV"", ""Pontuacao"": 125000.5 }, { ""IndiceNome"": ""S&P500"", ""Pontuacao"": 4500.2 } ] }"; RootType2 root2 = JsonSerializer.Deserialize<RootType2>(type2Json); foreach (Data item in root2.Value) { Console.WriteLine($"Índice: {item["IndiceNome"]}, Pontuação: {item["Pontuacao"]}"); }
错误代码对比(栈溢出原因)
如果之前的派生类是如下写法,会触发无限递归导致栈溢出:
// 错误示例,禁止使用 public class RootType1 : Root { public override List<Data> Value { get => Value; // 递归调用自身,无限循环 set => Value = value; } }
必须通过私有字段或泛型属性存储实际数据,避免直接访问属性本身。
内容的提问来源于stack exchange,提问作者Antônio Pragana
相关产品推荐
相关产品推荐

