为什么Json.Net 6不能将T反序列化为动态对象中的通用列表? (在第5版中工作)

时间:2015-06-09 14:34:08

标签: json.net

我从Json.net的版本5更新到版本6.0.8。但是,我的代码停止工作,我花了一段时间才明白,在以前的版本中,它能够处理泛型类型用列表实例化的情况。但现在,它并没有。我的问题是,是否有任何设置我需要调整以获得旧的行为?

在旧图书馆,班级

 public class Result<T> 
    {
        public T Data
        {
            get;
            set;
        }

        public int ResultCode
        {
            get;
            set;
        }
    }

适用于使用类似

实例化类的情况
Result<List<int>> result;

所以在我的代码中我做了类似

的事情
dynamic result = JsonConvert.DeserializeObject(result, typeof(JObject));
int firstValue = (int)result.Data[0];

但是,使用最新的Json.Net,它会失败并抛出异常(使用无效键值访问JObject值:0。期望对象属性名称。)。我发现的唯一工作是

var resultList = result.Data.ToObject<List<int>>();
int firstValue = resultList[0];
显然,这种失败的动机目的,我宁愿回到旧的行为。我可以做的任何事情告诉Json.net T可以是List&lt; int&gt; ?我看到它有关于它的元数据,因为$ type和$ values属性在动态对象的Result视图中可见。

感谢任何帮助,谢谢。

为帮助隔离问题并回答评论问题,我创建了一个测试应用。事实证明,TypeNameHandling.All选项是导致参数异常的原因。我在代码中添加了注释以显示好/坏序列化。是的,我认为我们的代码中需要All选项。

    using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ShowingBug
{
    public class InterestingResult
    {
        public string Information { get; set; }
    }

    public class Result<T> 
    {
        public T Data { get; set; }
        public int ResultCode { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var veryInteresting = new List<InterestingResult>();
            veryInteresting.Add(new InterestingResult() { Information = "Good" });

            Result<List<InterestingResult>> operationResult = new Result<List<InterestingResult>>();
            operationResult.Data = veryInteresting;
            operationResult.ResultCode = 1;

            JsonSerializerSettings serializerSettings = new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto
            };

            var json = JsonConvert.SerializeObject(operationResult, serializerSettings);
            dynamic result = JObject.Parse(json);
            string information = (string)result.Data[0].Information;

            Console.Out.WriteLine(information);

            //The above works, however after some digging... 
            // I found that the option we use is not Auto, but All

            serializerSettings = new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.All
            };

            json = JsonConvert.SerializeObject(operationResult, serializerSettings);
            result = JObject.Parse(json);

            // Now, you get an ArgumentException from Json.net 6.0.8 on the following line
            information = (string)result.Data[0].Information; 

            // It worked in previous version of Json.Net
            // I'm using .net 4.5.2 (if that makes a difference)
        }
    }
}

1 个答案:

答案 0 :(得分:1)

我在这里没有看到错误。问题是,即使您指定反序列化的对象类型应为Result<T>,您似乎也期望获得原始的JObject对象。这将永远不会有效,因为Result<T>不是JObject,而JObject无法保存自定义对象,例如Result<T>JObject只能包含JProperty个对象的集合,而这些对象只能包含从JToken派生的值。这是设计的。

当您调用JsonConvert.DeserializeObject(json, typeof(JObject))时,即使接收变量声明为JObject,也会强制返回对象为dynamic。同样,JObject.Parse()将始终返回JObject

如果你想恢复你的原始对象,尊重JSON中的嵌入式类型信息,你应该使用JsonConvert.DeserializeObject() 的重载而不用类型,并传递相同的{用于序列化的{1}}:

JsonSerializationSettings