使用嵌套派生对象对/从JSON

时间:2016-06-17 12:26:07

标签: c# json

是否有C#库可以在一次调用中序列化.NET / C#强类型对象的树状结构?

编辑:我希望能够将JSON反序列化为类型对象的变量(或其他一些根类,但最好是对象),然后通过在此变量上调用GetType()来找出我刚刚反序列化的内容。所以每个类的每个实例的类型(bool / int / float / string除外)和每个List<>应该作为序列化JSON的一部分存储并自动检索。

例如,如果我有这些C#类:

public class House
{
    public int Number;
    public List<Room> Rooms;
}

public class Room
{
    public string Name;
    public int Floor;
}

public class Bathroom : Room
{
    public bool IsWet;
}

并初始化我的内存数据结构(注意我使用通用List类,而不是C#数组):

House myHouse = new House();
myHouse.Number = 13;
myHouse.Rooms = new List<Room>();
myHouse.Rooms.Add(new Room());
myHouse.Rooms[0].Name = "some room";
myHouse.Rooms[0].Floor = 0;
myHouse.Rooms.Add(new Bathroom());
myHouse.Rooms[0].Name = "other room";
myHouse.Rooms[0].Floor = 3;
myHouse.Rooms[0].IsWet = true;

之后我希望能够打出这样的话:

string jsonHouse = JSON.Serialize(myHouse);

在我的jsonHouse变量中获取(例如)这个(编辑:请注意,它将每个类的类型存储为JSON的一部分。还要注意存储在List中的派生类BathRoom的实例)

{
  "class": "House",
  "Number": "13",
  "Rooms": [
    {
      "class": "Room",
      "Name": "some room"
      "Floor": "0",
    },
    {
      "class": "Bathroom",
      "Name": "other room"
      "Floor": "0",
      "IsWet": "true",
    },
  ],
}

最后打电话给这样的话:

House copyOfMyHouse = JSON.Deserialize(jsonHouse);
编辑:这(右上方)的电话似乎有误导性。而不是上面的调用我应该期望反序列化是这样的:

object copyOfMyHouse = JSON.Desrialize(jsonHouse);

要在我的copyOfMyHouse变量(类型为object)中获取类House的实例,而不指定JSON.Deserialize我期望从哪种类型 - 我可能不会提前知道它。

获取myHouse变量的精确副本,其中包含List泛型类的实例,其中包含对Room类的两个实例的精确副本的引用。

是否有用C#编写的JSON序列化程序可以做到这一点?

优选FOSS / FLOSS可以(合法地)用于商业项目。

JSON字符串的格式可能与我上面作为示例使用的格式不同(例如,您提出的解决方案可能将List存储为JSON对象而不是数组,其他文本格式如BSON或XML是可接受的) 对任意数量的嵌套级别使用单次调用是必需的 - 否则任何JSON序列化程序都适合。 还需要将Dictionary序列化为JSON对象的能力。

如果我对我所寻找的内容的描述不清楚,请提出澄清问题。

3 个答案:

答案 0 :(得分:2)

基本上,您希望序列化/反序列化包含派生类型的对象。解决方案是使用Json.NET。它非常简单易用。以下是您的数据示例:

House myHouse = new House();
myHouse.Number = 13;

myHouse.Rooms = new List<Room>();

Room room1 = new Room();
room1.Name = "some room";
room1.Floor = 0;
myHouse.Rooms.Add(room1);

Room room2 = new Room();
room2.Name = "other room";
room2.Floor = 3;
myHouse.Rooms.Add(room2);

Bathroom bathroom = new Bathroom();
bathroom.Name = "Bathroom";
bathroom.Floor = 2;
bathroom.IsWet = true;
myHouse.Rooms.Add(bathroom);

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Auto;

string json = JsonConvert.SerializeObject(myHouse, settings);
Console.WriteLine("Serialize finished!");

House house = JsonConvert.DeserializeObject<House>(json, settings);
Console.WriteLine($"House number: {house.Number}; Total rooms: {house.Rooms.Count}");

foreach (Room room in house.Rooms)
{
    if (room is Bathroom)
    {
        var temp = room as Bathroom;
        Console.WriteLine($"Room name: {temp.Name}, wet: {temp.IsWet}");
    }
    else
    {
        Console.WriteLine($"Room name: {room.Name}");
    }
}
Console.WriteLine("Deserialize finished!");

Console.ReadLine();

以下是序列化后获得的JSON字符串:

{
  "Number": 13,
  "Rooms": [
    {
      "Name": "some room",
      "Floor": 0
    },
    {
      "Name": "other room",
      "Floor": 3
    },
    {
      "$type": "DemoApp.Bathroom, DemoApp",
      "IsWet": true,
      "Name": "Bathroom",
      "Floor": 2
    }
  ]
}

在反序列化字符串后你得到了对象。

答案 1 :(得分:1)

Newtonsoft.JSON(有时称为JSON.NET)很好,可以作为NuGet包使用。然后你可以写下这样的东西:

var value = new { ID = 1, Name="test"};
string serialized = JsonConvert.SerializeObject(value);

反序列化(最简单的选项,但有很多好的方法可以做到):

result = JsonConvert.DeserializeObject(jsonResponse);

答案 2 :(得分:1)

虽然其他答案已经提供了很好的解决方案,但这里有一个使用DataContractJsonSerializer类。

var jsonString = "";
var jsonSerializer = new DataContractJsonSerializer(typeof(House));

using (var memoryStream = new MemoryStream())
using (var streamReader = new StreamReader(memoryStream))
{
    jsonSerializer.WriteObject(memoryStream, myHouse);
    memoryStream.Position = 0;
    jsonString = streamReader.ReadToEnd();
}

Console.Write("JSON form of Person object: ");
Console.WriteLine(jsonString);