C# JSON 将文件反序列化为对象列表失败,并将字符串转换为集合错误

Posted

技术标签:

【中文标题】C# JSON 将文件反序列化为对象列表失败,并将字符串转换为集合错误【英文标题】:C# JSON deserialize a file into object list fails with convert String to Collection error 【发布时间】:2021-11-08 21:21:14 【问题描述】:

我有一个学校的小项目,我们在这里处理一些 json 的东西。 我可以将对象列表写入 JSON,并且该文件是有效的 JSON 格式。 没有,一旦我加载了相同的文件,我确实会收到一个错误,抱怨无法转换。这是消息:

Newtonsoft.Json.JsonSerializationException
  HResult=0x80131500
  Message=Error converting value "[
  
    "ID": 500455154,
    "Title": "GameOne",
    "MinAge": 14,
    "Price": 12.8,
    "State": "New",
    "Players": 4
  ,
  
    "ID": 860100321,
    "Title": "Gametwo",
    "MinAge": 14,
    "Price": 12.8,
    "State": "New",
    "Players": 4
  ,
  
    "ID": 358239485,
    "Title": "Gamethree",
    "MinAge": 14,
    "Price": 12.8,
    "State": "New",
    "Players": 4
  
]" to type 'System.Collections.Generic.List`1[Ludothek.Game]'. Path '', line 1, position 513.
  Source=Newtonsoft.Json
  StackTrace:
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Ludothek.DATA.loadData_Games() in epos\Ludothek\Ludothek\DATA.cs:line 71
   at Ludothek.Program.Main(String[] args) in \r\Program.cs:line 16

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
ArgumentException: Could not cast or convert from System.String to System.Collections.Generic.List`1[Ludothek.Game].

这是我加载此文件并将其推送到现有游戏列表中的功能:

public List<Game> loadData_Games()
        
            var Gl = new List<Game>();
            string[] files = Directory.GetFiles(folder, "games.json");
            foreach (var file in files)

                using (StreamReader sr = new StreamReader(file))
                
                    using (JsonReader jsr = new JsonTextReader(sr)) 
                        var Serializer = new JsonSerializer();

                        Gl = (List<Game>)Serializer.Deserialize(jsr, typeof(List<Game>));
// above is where it hits the fan...
                    


                

        
            return Gl;
        

当然还有游戏类:

public class Game : AbstGame
    

        [JsonProperty("ID")]
        public override int ID  get ; 
        [JsonProperty("Title")]
        public override string Title  get ; set ; 
        [JsonProperty("MinAge")]
        public override int MinAge  get ; set ; 
        [JsonProperty("Price")]
        public override double Price  get; set ; 
        [JsonProperty("State")]
        public override string State  get; set ; 
        [JsonProperty("Players")]
        public int Players  get; set; 
        
        public Game(string title, int minAge, double price,string state, int players)
        
            Random rnd = new Random();
            ID = rnd.Next(1, 999999999);
            Title = title;
            MinAge = minAge;
            Price = price;
            State = state;
            Players = players;

        

我是这样写的:

        public void backUp_Games(List<Game> games)
        
            string filename = "games";
               string jsonGames = JsonConvert.SerializeObject(games,Formatting.Indented);
            backUp(filename, jsonGames);


        
        public void backUp(string fileName ,string json)
        
            string filename = @"C:\.....\Desktop\JsonTest\"+fileName+".json"; // not the actual path ;)
            File.WriteAllText(filename, JsonConvert.SerializeObject(json,Formatting.Indented));

        

我真的在互联网上四处寻找解决这个问题的方法,并尝试了其他几种方法。我无法发现问题。有没有其他人看到它并可以给我一个提示?

我在代码中所做的就像生成具有某些属性的游戏列表。一旦窗口关闭,我会将那个游戏对象列表推送到 json 中并保护它,一旦我们打开它就会重新加载。 所以它必须从json中获取对象列表。

提前非常感谢!

【问题讨论】:

var games = JsonConvert.DeserializeObject&lt;List&lt;Game&gt;&gt;(json);; 与发布的 Json 和 Game 类一起使用.. 可能是转义双引号的问题。基于此链接:newtonsoft.com/json/help/html/readjsonwithjsontextreader.htm JsonTextReader 可能只接受带单引号的 json。尝试使用 @stuartd 建议的反序列化器。 大家好,Christoph 说的不对,我真的做了两次连载部分。一旦我将其更改为只执行一次序列化部分,一切正常,JSON 看起来也正确。感谢您的帮助!创建 JSON 而不是反序列化它是一个问题。 【参考方案1】:

并且此文件是有效的 JSON 格式

是的,它是有效的 JSON,但不是您所期望的。您编写的文件只有一个 JSON 字符串。

简化示例:

"foo"

这是有效的 json。这只是一个字符串。你也这样做,但字符串内容看起来像 JSON。

"\"foo\": \"bar\""

这仍然只是一个字符串,没有 JSON 对象。

这就是您收到错误消息的原因:无法从 System.String 转换或转换为 System.Collections.Generic.List`1[Ludothek.Game]。

这就是你要做的......

string jsonGames = JsonConvert.SerializeObject(games,Formatting.Indented);
// string jsonGames is the JSON you want but then you do...
File.WriteAllText(filename, JsonConvert.SerializeObject(json,Formatting.Indented));

因此,您执行了两次 JSON 编码,并且 JSON 编码一个 JSON 字符串将产生一个如上所述的字符串。

解决方案:只编码一次。

【讨论】:

嗨,克里斯托夫,非常感谢!我在反序列化部分非常努力,以至于我没有仔细检查序列化部分。确实!我做了两次序列化部分。我头上的灰烬......但感谢您的快速帮助!大赞!现在它就像一个魅力。

以上是关于C# JSON 将文件反序列化为对象列表失败,并将字符串转换为集合错误的主要内容,如果未能解决你的问题,请参考以下文章

将 JSON 字符串反序列化为多个 C# 对象

无法将 JSON 字符串反序列化为 C# 对象

需要帮助将 XML 文件反序列化为对象 C#

将特定 JSON 字段反序列化为 Unity 中的对象列表

无法将 JSON 数组反序列化为 C# 对象 [关闭]

如何将 XML 反序列化为 C# 中的对象? [复制]