繁体   English   中英

Newtonsoft JSON.NET反序列化错误

[英]Newtonsoft JSON.NET Deserialization error

我在单个文件中有一堆长json输出。 我需要读取这些文件并将它们反序列化为最初生成json的实体(我可以访问原始实体)。 每个文件都有通过序列化IEnumerable<Response<MyEntity>>类型的对象生成的json输出。

我试图反序列化时遇到异常,但我不明白为什么。 这是我尝试反序列化:

List<string> jsonOutputStrings;
// Read json from files and populate jsonOutputStrings list
List<Response<MyEntity>> apiResponses = new List<Response<MyEntity>>();

foreach (string json in jsonOutputStrings)
{
    apiResponses.AddRange(JsonConvert.DeserializeObject<List<Response<MyEntity>>>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }).ToList());
}

我也尝试反序列化到IEnumerable而不是列表:

apiResponses.AddRange(JsonConvert.DeserializeObject<IEnumerable<Response<MyEntity>>>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }).ToList());

我得到以下异常:

Newtonsoft.Json.dll发生了'Newtonsoft.Json.JsonSerializationException'类型的第一次机会异常

附加信息:无法创建和填充列表类型System.Linq.Enumerable + WhereSelectListIterator`2 [Entities.Requirement,Entities.RequirementEntity]。 路径'$ values [0] .ReturnedEntity.Summaries。$ values [0] .Requirements。$ values',line 1,position 715。

整个json太长而无法发布(并且还包含一些机密数据)但我确实在json中找到了一个包含此内容的地方:

"Requirements":{"$id":"7","$type":"System.Linq.Enumerable+WhereSelectListIterator`2[[Entities.Requirement, Entities],[Entities.RequirementEntity, API.Entities]], System.Core","$values":[...]}

在我尝试反序列化的实体(最初序列化的IEnumerable<Entities.RequirementEntity> )中, Requirements的类型为IEnumerable<Entities.RequirementEntity>

对我来说, MyEntity序列化是如何工作的,但反序列化到同一类型却没有意义。 我该如何解决这个问题?

您必须浏览Response<>MyEntity并查看集合的初始化方式。 这告诉我们某些类中的一个集合是使用linq中的Where方法创建的。 您可以通过执行以下代码重现此错误:

class MyEntity
{
    public MyEntity()
    {
        Data = new List<string>().Where(x => true);
    }

    public IEnumerable<string> Data { get; set; }

}

class Program
{
    static void Main(string[] args)
    {
        string data = @"[{""Data"":[""a"",""b""]}]";
        var j = JsonConvert.DeserializeObject<IEnumerable<MyEntity>>(data);
    }
}

另一种可能性是在json中使用元数据。 那么你有2个解决方案:

  • TypeNameHandling设置为TypeNameHandling.None (正如评论中提到的那样);
  • 将字符串中的工作类型替换为工作类型

当您拥有IEnumerable<BaseType>并且该列表包含BaseType子类型时,使用TypeNameHandling.None可能会导致exmaple的反序列化错误。

在这种情况下,你应该选择第二种选择。 基本上,您应该替换任何未反序列化的类型,并将其替换为例如List

示例代码:

class MyEntity
{
    public IEnumerable<string> Data { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        IList<MyEntity> entities = new MyEntity[] {
            new MyEntity { Data = new [] { "1", "2" }.Where(x => x != string.Empty) },
            new MyEntity { Data = new [] { "A", "B" }.AsQueryable().Where(x => x != string.Empty) },
            new MyEntity { Data = new List<string> { "A", "B" } },
        };

        string data = JsonConvert.SerializeObject(entities, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
        data = Regex.Replace(data, "\"\\$type\":\\s+\"System.Linq.Enumerable\\+WhereArrayIterator(.+?), System.Core\",", "\"$type\": \"System.Collections.Generic.List$1, mscorlib\",", RegexOptions.Singleline);

        var j = JsonConvert.DeserializeObject<IEnumerable<MyEntity>>(data, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
    }
}

序列化实体中是否有Linq结果? 也许定义为IEnumerable并填充了Linq Where结果? 这似乎是你的问题所在。 您应该在序列化之前将其转换为List或Array。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM