【问题标题】:Using Newtonsoft.Json, how do I deserialize JSON to a type with an IEnumerable property containing an interface type?使用 Newtonsoft.Json,如何将 JSON 反序列化为具有包含接口类型的 IEnumerable 属性的类型?
【发布时间】:2012-08-30 13:23:22
【问题描述】:

我正在使用一个发送 JSON 的 RESTful Web 服务,我尝试使用 HttpContent.ReadAsAsync<T> 对其进行反序列化。我尝试反序列化的类型声明了一个属性,该属性返回一个包含接口类型的 IEnumerable。这段代码 sn-p 演示了我试图反序列化为的类型:

public class Data
{
    public IEnumerable<IChild> Children { get; set; };
}

问题在于 Newtonsoft.Json,底层 HttpContent.ReadAsAsync&lt;T&gt; 不理解如何反序列化 IChild 类型的对象,后者是一个接口。如何向 Newtonsoft.Json 指定如何将 IChild 反序列化为具体类型?

【问题讨论】:

  • @L.B 在这种情况下有关系吗?问题只是如何告诉 Newtonsoft.Json 将接口(IChild)转换为具体类型 f.e.x Child。

标签: .net json serialization json.net


【解决方案1】:

您可以使用自定义Converter 告诉 JSON.NET 如何反序列化该接口的类型。下面的代码显示了一个示例。

public class StackOverflow_12197892
{
    public class Data
    {
        public IEnumerable<IChild> Children { get; set; }

        public override string ToString()
        {
            return string.Format("Data{{Children=[{0}]}}",
                string.Join(", ", Children.Select(c => string.Format("{0}/{1}", c.Name, c.IsFemale ? "girl" : "boy"))));
        }
    }
    public interface IChild
    {
        string Name { get; }
        bool IsFemale { get; }
    }
    public class Son : IChild
    {
        public Son(string name)
        {
            this.Name = name;
        }

        public string Name { get; private set; }
        public bool IsFemale { get { return false; } }
    }
    public class Daughter : IChild
    {
        public Daughter(string name)
        {
            this.Name = name;
        }

        public string Name { get; private set; }
        public bool IsFemale { get { return true; } }
    }
    class ChildConverter : Newtonsoft.Json.JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(IChild).IsAssignableFrom(objectType);
        }

        public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
        {
            JObject obj = serializer.Deserialize<JToken>(reader) as JObject;
            if (obj != null)
            {
                bool isFemale = obj["isFemale"].ToObject<bool>();
                string name = obj["name"].ToObject<string>();
                if (isFemale)
                {
                    return new Daughter(name);
                }
                else
                {
                    return new Son(name);
                }
            }
            else
            {
                return null;
            }
        }

        public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    public static void Test()
    {
        Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
        serializer.Converters.Add(new ChildConverter());
        string json = "{'Children':[{'name':'John',isFemale:false},{'name':'Mary',isFemale:true}]}".Replace('\'', '\"');
        var obj = serializer.Deserialize(new StringReader(json), typeof(Data));
        Console.WriteLine(obj);
    }
}

【讨论】:

  • 谢谢。不过,您如何将转换器与 HttpContent.ReadAsAsync&lt;T&gt; 集成,因为这会间接调用 Newtonsoft.Json?
  • 您需要在内容的格式化程序中设置转换器。
  • 我通过在IChild 上设置[ConverterAttribute] 来配置转换器。
【解决方案2】:

json.net 提供的开箱即用支持非常简单,您只需在序列化和反序列化时使用以下 JsonSettings:

JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings()
                                                                                               {
                                                                                                 TypeNameHandling = TypeNameHandling.Objects,
                                                                                               TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
                                                                                           });

对于反序列化使用下面的代码:

JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
                                                       new JsonSerializerSettings()
                                                           {TypeNameHandling = TypeNameHandling.Objects});

只需记下 JsonSerializerSettings 对象初始化程序,这对您很重要。

【讨论】:

    猜你喜欢
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多