【问题标题】:Save and Load C# list of different types from JSON从 JSON 保存和加载不同类型的 C# 列表
【发布时间】:2019-01-27 21:02:28
【问题描述】:

我正在使用 JSON 序列化和反序列化 c# 中的列表。如果列表由单一类型的对象组成,则一切正常。我的目标是找到一种方法来存储不同类型的对象的列表(或队列或类似的东西),我可以稍后加载和迭代并执行操作。我可以将我的序列化分解为多个列表,但是按照添加的顺序迭代对象很重要,因此让它们都成为同一数据结构的一部分是理想的。

我尝试拥有一个它们都继承自的 DataModelBase 类,并拥有一个 DataModelBase 类型的列表,它在运行时和保存时工作,但我无法使用加载/反序列化功能。我也尝试使用接口并将自定义参数传递给我的反序列化调用,但这导致我的 Unity 应用程序崩溃。有没有更好的方法来实现我想要实现的目标?

这是我的加载函数:

public static T LoadData<T>(string path)
    {
        using (var reader = new StreamReader(path))
        {
            var fileContents = reader.ReadToEnd();
            reader.Close();
            reader.Dispose();
            return JsonConvert.DeserializeObject<T>(fileContents);
        }
    }

尝试将列表中的条目转换为我的类类型时,我通常遇到的错误是:RuntimeBinderException:无法隐式转换类型Newtonsoft.Json.Linq.JObject' toType 我正在尝试转换为'

【问题讨论】:

  • 如果您想跟踪添加项目的顺序,请在列表中跟踪它>
  • 这些类型是否相关,例如他们有基类吗?
  • 是的,它们都有一个基类,它们都继承自。

标签: c# json list serialization deserialization


【解决方案1】:

将 json 解析为 Dynamic.它应该给你你想要的灵活性,但可能有点慢

Deserialize json object into dynamic object using Json.net

您也可以使用多态性

what's the difference between inheritance and polymorphism?

【讨论】:

    【解决方案2】:

    我将使用TypeNameHandling 设置将类型数据保存在已保存的 JSON 中。这很可能会解决您看到的反序列化问题。

    来自链接的文档:

    Stockholder stockholder = new Stockholder
    {
        FullName = "Steve Stockholder",
        Businesses = new List<Business>
        {
            new Hotel
            {
                Name = "Hudson Hotel",
                Stars = 4
            }
        }
    };
    
    string jsonTypeNameAll = JsonConvert.SerializeObject(stockholder, Formatting.Indented, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    });
    
    Console.WriteLine(jsonTypeNameAll);
    // {
    //   "$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests",
    //   "FullName": "Steve Stockholder",
    //   "Businesses": {
    //     "$type": "System.Collections.Generic.List`1[[Newtonsoft.Json.Samples.Business, Newtonsoft.Json.Tests]], mscorlib",
    //     "$values": [
    //       {
    //         "$type": "Newtonsoft.Json.Samples.Hotel, Newtonsoft.Json.Tests",
    //         "Stars": 4,
    //         "Name": "Hudson Hotel"
    //       }
    //     ]
    //   }
    // }
    
    string jsonTypeNameAuto = JsonConvert.SerializeObject(stockholder, Formatting.Indented, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto
    });
    
    Console.WriteLine(jsonTypeNameAuto);
    // {
    //   "FullName": "Steve Stockholder",
    //   "Businesses": [
    //     {
    //       "$type": "Newtonsoft.Json.Samples.Hotel, Newtonsoft.Json.Tests",
    //       "Stars": 4,
    //       "Name": "Hudson Hotel"
    //     }
    //   ]
    // }
    
    // for security TypeNameHandling is required when deserializing
    Stockholder newStockholder = JsonConvert.DeserializeObject<Stockholder>(jsonTypeNameAuto, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto
    });
    
    Console.WriteLine(newStockholder.Businesses[0].GetType().Name);
    // Hotel
    

    【讨论】:

    • 添加类型名称处理解决了我的问题。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多