json C#如何正确地将数组中的多个自定义对象反序列化为一个对象?

ix0qys7i  于 2023-08-08  发布在  C#
关注(0)|答案(5)|浏览(124)

我正在用数组检索一个JSON对象,该数组包含多个对象类型。
假设我检索了一个JSON有效负载,看起来像这样:

{
   "Lines": [
   {
       "PropertyA": "A",
       "PropertyB": "B"
   },
   {
       "Property01": 1,
       "Property02": 2
   }]
}

字符串
我想将其反序列化为单个对象列表。
范例:

public List<Line> Lines;


这样我就可以把这个物体和我期望的物体进行比较了。
到目前为止我有:

public class Class1
{
    public string PropertyA = "A";
    public string PropertyB = "B";
}

public class Class2
{
    public int Property01 = 01;
    public int Property02 = 02;
}

public class MainClass
{
    public List<dynamic> Lines;
}

class Program
{
    static void Main(string[] args)
    {
        string json = "{\r\n \"Lines\": [\r\n {\r\n \"PropertyA\": \"A\",\r\n \"PropertyB\": \"B\"\r\n },\r\n {\r\n \"Property01\": 1,\r\n \"Property02\": 2\r\n }]\r\n}";

        MainClass actual = JsonConvert.DeserializeObject<MainClass>(json);

        MainClass expected = new MainClass()
        {
            Lines = new List<dynamic>()
            {
                new Class1(),
                new Class2()
            }
        };

        actual.Should().BeEquivalentTo(expected);
    }
}


如有任何帮助,将不胜感激!
干杯

2mbi3lxu

2mbi3lxu1#

你可以验证适当的名称和反序列化在正确的对象像这样

class Program
{
    static void Main(string[] args)
    {

        var class1List = new List<Class1>();
        var class2List = new List<Class2>();
        var genericList = new List<dynamic>();

        var actual = JsonConvert.DeserializeObject<dynamic>(json);
        foreach (var item in actual.Lines)
        {

            string itemJson = JsonConvert.SerializeObject(item);
            if (itemJson.Contains("PropertyA"))
            {
                var class1 = JsonConvert.DeserializeObject<Class1>(itemJson);
                class1List.Add(class1);
                genericList.Add(class1);
            }
            else
            {
                var class2 = JsonConvert.DeserializeObject<Class2>(itemJson);
                class2List.Add(class2);
                genericList.Add(class2);
            }
        }
    }
}

public class Class1
{
    public string PropertyA;
    public string PropertyB;
}

public class Class2
{
    public int Property01;
    public int Property02;
}

字符串

wqnecbli

wqnecbli2#

首先将字段更改为属性。那么这里最简单的方法是创建一个公共对象,代表两个对象,如下所示:

public class Class1
{   
    public string PropertyA {get;set;}
    public string PropertyB {get;set;}
    public int Property01 {get;set;}
    public int Property02 {get;set;}
}

public class MainClass
{
    public List<Class1> Lines;
}

字符串
和反序列化看起来像这样:

MainClass actual = JsonConvert.DeserializeObject<MainClass>(json);


如果将Class1的类定义更改为具有可空属性的对象,您将能够检测json中是否存在属性以区分两个对象:

public class Class1
{   
    public string PropertyA {get;set;}
    public string PropertyB {get;set;}
    public int? Property01 {get;set;}
    public int? Property02 {get;set;}
}


另一种方法是使用JArray并使用此对象继续执行您的逻辑:

JArray arr = JArray.Parse(json);

yebdmbv4

yebdmbv43#

您可以定义一个抽象类LineClass1Class2将继承该抽象类:

public abstract class Line
{
}

public class Class1 : Line
{
    public string PropertyA = "A";
    public string PropertyB = "B";
}

public class Class2 : Line
{
    public int Property01 = 01;
    public int Property02 = 02;
}

字符串
您的MainClass将使用Line列表,而不是动态:

public class MainClass
{
    public List<Line> Lines { get; set; }
}


然后,为了处理Json Serializer中Class1Class2的示例化,可以定义一个JsonConverter

public class LineConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Line));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var line = default(Line);

        if (jsonObject["PropertyA"] != null)
        {
            line = new Class1();
        }
        else if (jsonObject["Property01"] != null)
        {
            line = new Class2();
        }

        serializer.Populate(jsonObject.CreateReader(), line);
        return line;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException(); // Implement if you're serializing the objects back to JSON
    }
}


并在JsonSerializer设置中使用此转换器:

internal class Program
{
    static void Main()
    {
        string json = "{\r\n \"Lines\": [\r\n {\r\n \"PropertyA\": \"A\",\r\n \"PropertyB\": \"B\"\r\n },\r\n {\r\n \"Property01\": 1,\r\n \"Property02\": 2\r\n }]\r\n}";

        var serializerSettings = new JsonSerializerSettings();
        serializerSettings.Converters.Add(new LineConverter());
        MainClass actual = JsonConvert.DeserializeObject<MainClass>(json, serializerSettings);

        MainClass expected = new MainClass()
        {
            Lines = new List<Line>()
            {
                new Class1(),
                new Class2()
            }
        };

        actual.Should().BeEquivalentTo(expected);
    }
}

yqkkidmi

yqkkidmi4#

这真的取决于你的用例,但是一个替代的解决方案可能是 * 不 * 使用混合类型的数组,并将每个类型分解为它们自己的属性,即。

{
   "Lines": {
        "AlphaLines": [
            {
                "PropertyA": "A",
                "PropertyB": "B",
                "Index": 0
            }
        ],
        "NumericLines": [
            {
                "Property01": 1,
                "Property02": 2,
                "Index": 1
            }
        ]
    }
}

字符串
这真的取决于您是否拥有传入JSON的结构,并且您是否有能力根据需要重新格式化。但另一方面,它使 * 序列化部分超级简单 *。
如果您与每个包含Index属性的接口共享

public interface ILine
{
    int Index {get;set;}
}


然后你就可以按原来的顺序把它们缝回去了

var allLines = p.Lines.AlphaLines.Cast<ILine>().Concat(p.Lines.NumericLines).OrderBy(x => x.Index);

Demo in DotNetFiddle

同样,可能不是对每个人都最好的,但实际上取决于数据的结构,以及混合了多少不同的类。

gstyhher

gstyhher5#

要在C#中正确地将数组中的多个自定义对象反序列化为一个对象,可以使用Newtonsoft.Json(也称为Json.NET)库。下面是一个如何做到这一点的例子:

using Newtonsoft.Json;
using System.Collections.Generic;

public class Line
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}

public class MainClass
{
public List<dynamic> Lines { get; set; }
}

class Program
{
static void Main(string[] args)
{
string json = "{\"Lines\": [{\"PropertyA\": \"A\", \"PropertyB\": \"B\"}, {\"Property01\": 1,}"

字符串

相关问题