【问题标题】:C# Newtonsoft Json Converter Deserializing Generic to concrete on the flyC# Newtonsoft Json 转换器将泛型反序列化为运行中的具体
【发布时间】:2018-03-02 11:28:52
【问题描述】:

我的 API 返回一个简单的对象

{
"Code":0,
"Message":"String",
"Data":"Can Be Anything"
}

数据可以是字符串或任何其他对象,如 Person、Cat、List 等...

我将响应映射到 c# 将数据作为对象,假设我将此对象称为“响应”

我想知道当我反序列化时是否有可能我通知 Data 将是的类型并进行转换以理解并将 Data 转换为我传递的类型。

应该是这样的

public static Response ToWrapper<T>(this string json)
{
    return JsonConvert.DeserializeObject<Response>(json, new Converter<T>());
}

在这个例子中,我会说 Data 是一个名为 Person 的虚拟类,带有属性字符串 Name、字符串 Email 和 int Age,所以响应是

string json = "
{
   "Code":1,
   "Message":"OK",
   "Data": {"Name": "Patrick", "Email": "aa@aaa.com", "Age" : 25}
}"

所以在我的代码的某些点我会

var ResponseWrapper = json.ToWrapper<Person>();

string personName = ResponseWrapper.Data.Name;  
string personEmail = ResponseWrapper.Data.Email;
int personAge = ResponseWrapper.Data.Age; //<----- NO CAST NEEDED

转换器会将对象数据转换为个人数据!!!

转换器我尝试了一些代码但没有成功!我尝试了很多代码,我可以从这里得到的关闭How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

public class PersonConverter<T> : JsonCreationConverter<T>
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        protected override T Create(Type objectType, JObject jObject)
        {
            T obj = Activator.CreateInstance<T>();

            if (FieldExists("Data", jObject))
            {
                return obj;
            }
            else
                return obj;
        }

        private bool FieldExists(string fieldName, JObject jObject)
        {
            return jObject[fieldName] != null;
        }
    }

    public abstract class JsonCreationConverter<T> : JsonConverter
    {
        /// <summary>
        /// Create an instance of objectType, based properties in the JSON object
        /// </summary>
        /// <param name="objectType">type of object expected</param>
        /// <param name="jObject">
        /// contents of JSON object that will be deserialized
        /// </param>
        /// <returns></returns>
        protected abstract T Create(Type objectType, JObject jObject);

        public override bool CanConvert(Type objectType)
        {
            return true; // typeof(T).IsAssignableFrom(objectType);
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override object ReadJson(JsonReader reader,
                                        Type objectType,
                                         object existingValue,
                                         JsonSerializer serializer)
        {
            // Load JObject from stream
            JObject jObject = JObject.Load(reader);

            // Create target object based on JObject
            T target = Create(objectType, jObject);

            // Populate the object properties
            serializer.Populate(jObject.CreateReader(), target);

            return target;
        }
    }

【问题讨论】:

    标签: c# json generics json.net


    【解决方案1】:

    我认为最好的前进路径是使用将CodeMessage 的反序列化卸载到JObject,然后使用JsonConvert 反序列化数据对象。

    https://dotnetfiddle.net/bP2Ew6

    using System;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    public class Program
    {
        public static void Main()
        {
            string json = @"
                {
                   ""Code"":1,
                   ""Message"":""OK"",
                   ""Data"": {""Name"": ""Patrick"", ""Email"": ""aa@aaa.com"", ""Age"" : 25}
                }";
    
            Console.WriteLine(json);
    
            var response=json.ToWrapper<Person>();
    
            Console.WriteLine("Name: "+response.Data.Name);
            Console.WriteLine("Email: "+response.Data.Email);
            Console.WriteLine("Age: "+response.Data.Age);
        }
    }
    
    public class Person{
        public string Name {get;set;}
        public string Email {get;set;}
        public int Age {get;set;}
    }
    
    public class Response<T>{
        public int Code {get;set;}
        public string Message {get;set;}
        public T Data {get;set;}
    }
    
    public static class ResponseExtensions {
        public static Response<T> ToWrapper<T>(this string json){
    
            var o=JObject.Parse(json);
            var data=JsonConvert.DeserializeObject<T>(o["Data"].ToString());
    
            return new Response<T>{
                Code=(int)o["Code"],
                Message=(string)o["Message"],
                Data=data
            };
        }
    }
    

    【讨论】:

    • Michael,它适用于复杂对象(人或任何自定义类)。现在的问题是字符串、int、float 等普通对象......因为数据不会是 json字符串它将只是普通对象结果.. dotnetfiddle.net/QDOUQn 要解决这个问题,我只需比较 T 如果是字符串,整数,因此一旦对象已经是我想要的值,就不需要反序列化。我现在的问题是,这是否是处理普通物体的最佳方式......干杯!!!!
    • 您是否尝试过使用.ToWrapper&lt;string&gt;().ToWrapper&lt;int&gt;().ToWrapper&lt;float&gt;()
    • 不起作用...我的 dal/service 用于简单的事情只返回普通对象,而 JsonConvert 想要一个 json(带有 json 的字符串,如 {"x" : "WYZ"})所以它可以反序列化...我解决了放置一个 IF 并检查 typeof(T) == typeof(string) 所以它就像 (string)o["Data"] 不传递给 JsonConvert.DeserializeObject .... 谢谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多