使用 JSON.Net 的 C# JSON 字符串反序列化

标签 c# json serialization json.net

我会有如下所示的 JSON 字符串,需要将其反序列化为下面的类

{
    "Id":"1",
    "Names":{
        "string":"Surya"
    },
    "ClassTypes":{
        "Types":[
            {
                "TypeId":"1",
                "TypeName":"First Name"
            },
            {
                "TypeId":"2",
                "TypeName":"Last Name"
            }
        ]
    },
    "Status":"1",
    "DOB":"23/12/2014"
}

类定义

public class MyClass
{
    public int Id { get; set; }
    public IList<string> Names { get; protected set; }
    public IList<Types> ClassTypes { get; protected set; }
    public StatusType Status { get; set; }
    public DateTime DOB { get; set; }

    public MyClass()
    {
        Names = new List<string>();
        ClassTypes = new List<Types>();
        Status = StatusType.Active;
    }
}
public class Types
{
    public int TypeId { get; set; }
    public string TypeName { get; set; }
}

public enum StatusType
{
    Active = 0,
    InActive = 1
}

我使用了下面的反序列化代码,但是出现了错误

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new IncludeNonPublicMembersContractResolver();
JsonConvert.DeserializeObject<MyClass>(jsonString, serializerSettings);

public class IncludeNonPublicMembersContractResolver : DefaultContractResolver
{
    public IncludeNonPublicMembersContractResolver()
    {
        DefaultMembersSearchFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
    }
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var members = base.GetSerializableMembers(objectType);
        return members.Where(m => !m.Name.EndsWith("k__BackingField")).ToList();
    }

}

错误详情

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IList`1[System.String]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Path 'Names.string', line 1, position 28.

注意 - 我无法通过 JSON 字符串和解决方案进行更改以使其更通用,因为其他类也需要这样做:(

最佳答案

一种方法是使用 JsonConverter:

  public class MyClass
    {
        public int Id { get; set; }
        [JsonProperty("Names"), JsonConverter(typeof(NamesConverter))]
        public IList<string> Names { get; protected set; }
        [JsonProperty("ClassTypes"), JsonConverter(typeof(TypesConverter))]
        public IList<Types> ClassTypes { get; protected set; }
        public StatusType Status { get; set; }
        [JsonProperty("DOB"), JsonConverter(typeof(DateTimeConverter))]
        public DateTime DOB { get; set; }

        public MyClass()
        {
            Names = new List<string>();
            ClassTypes = new List<Types>();
            Status = StatusType.Active;
        }

        public override string ToString()
        {
            return
                string.Format("ID: {0}\nNames:\n{1}\nClassTypes:\n{2}Status: {3}\nDOB: {4}",
                Id, string.Join("\n", Names), string.Join("\n", ClassTypes), Status, DOB);
        }
    }
    public class Types
    {
        public int TypeId { get; set; }
        public string TypeName { get; set; }

        public override string ToString()
        {
            return string.Format("\tTypeId: {0}\n\tTypeName: {1}\n", TypeId, TypeName);
        }
    }

    public enum StatusType
    {
        Active = 0,
        InActive = 1
    }

    class NamesConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(Dictionary<string, string>).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return serializer.Deserialize<Dictionary<string, string>>(reader).Values.ToList();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

    }
    class TypesConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(Dictionary<string,List<Types>>).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return serializer.Deserialize<Dictionary<string,List<Types>>>(reader)
                .Values.First().ToList();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

    }
    class DateTimeConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(string).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return DateTime.ParseExact(serializer.Deserialize<string>(reader), @"dd\/MM\/yyyy", null);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

    }

...

    var jsonobj = JsonConvert.DeserializeObject<MyClass>(json);
    Console.WriteLine(jsonobj);

打印:

Names:
Surya
ClassTypes:
    TypeId: 1
    TypeName: First Name

    TypeId: 2
    TypeName: Last Name
Status: InActive
DOB: 12/23/2014 12:00:00 AM

https://dotnetfiddle.net/EfQuET

两种方式 - 解析 json,但随后您需要更改属性 Names、ClassTypes 的访问权限或添加构造函数:

var jObject = JObject.Parse(json);
var names = new List<string> 
{ 
    jObject["Names"].Value<string>("string")
};
var types = jObject["ClassTypes"]["Types"]
    .Select(x => new Types
    {
        TypeId = x.Value<int>("TypeId"),
        TypeName = x.Value<string>("TypeName")
    })
        .ToList();
var data = new MyClass(names,types)
{
    Id = jObject.Value<int>("Id"),
    Status = (StatusType)Enum.Parse(typeof(StatusType),jObject.Value<string>("Status")),
    DOB = DateTime.ParseExact(jObject.Value<string>("DOB"), @"dd\/MM\/yyyy", null)
};

Console.WriteLine(data);

https://dotnetfiddle.net/HcPxT9

关于使用 JSON.Net 的 C# JSON 字符串反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32816252/

相关文章:

javascript - jQuery - 将 json 内容绑定(bind)到元素的简单方法?

javascript - 如何修复以下错误 : JSON. 解析 : unexpected end of data at line 1 column 1 of the JSON data?

c# - XmlSerializer - 反射(reflect)类型时出错

java - 无法使用 Jackson XmlMapper 反序列化包装列表

c# - Windows 8 - 在 For 循环中异步等待时出现线程错误

c# - Windows 窗体中的多级组合框

c#终结器抛出异常?

c# - 尝试序列化异常时忽略自定义解析器

json - 无法加载json映射Elasticsearch

.net - WCF序列化返回对象后关闭NHibernate session