牛顿软件 JSON.NET 反序列化错误



我在单个文件中有一堆长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.JsonSerializationException" 发生在 牛顿软件.Json.dll

其他信息:无法创建和填充列表类型 System.Linq.Enumerable+WhereSelectListIterator'2[Entities.Requirements,Entities.RequirementsEntity]. 路径 '$values[0]。ReturnEntity.Summaryries.$values[0].要求.$values', 第 1 行,位置 715。

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

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

在我尝试反序列化的实体(与最初序列化的实体相同(中,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 结果?看来这就是你的问题所在。在序列化之前,应将其转换为列表或数组。

相关内容

  • 没有找到相关文章