一、Json序列化忽略首字母大小写
方法一:使用JsonProperty特性,给类中每个属性增加JsonProperty(propertyName)特性
优点:可以指定任意名称序列化成员,不限于首字母大小写
缺点:此方法需要给每一个需要进行json序列化的对象的每一个成员配置特性,工作量较大
以下为测试类,使用JsonProperty特性示例:
public class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("age")]
public int Age { get; set; }
[JsonProperty("sex")]
public string Sex { get; set; }
}
以下为json序列化示例:
var p = new Person(){ Name = "张三", Age = 18, Sex = "男"};
var json = JsonConvert.SerializeObject(p);
方法二:无需设置JsonProperty特性,配置JsonSerializerSettings,使用JsonSerializerSettings将指定对象序列化为JSON字符串(此方法的优缺点正好与方法一互补)
var p = new Person(){ Name = "张三", Age = 18, Sex = "男"};
var setting = new JsonSerializerSettings
{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
};
var json = JsonConvert.SerializeObject(p, setting);
以上两种方式,序列化结果如下:
{"name":"张三","age":18,"sex":"男"}
二、Json字符串反序列化到子集对象
首先还是上面的测试对象Person,我们给他属性,并且建个新类继承Person。
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Sex { get; set; }
public Vocation Vocation { get; set; }
}
public enum Vocation
{
Teacher = 1,
Programmer = 2
}
public class Teacher : Person
{
public string Subject { get; set; }
}
public class Programmer : Person
{
public string Language { get; set; }
}
然后定义一个List<Person>的对象,里面存的有Person对象,也有他的子集Teacher等对象用于测试使用。
var list = new List<Person>()
{
new Person()
{
Name = "张三",
Age = 18,
Sex = "男"
},
new Programmer()
{
Name = "李四",
Age = 18,
Sex = "女",
Language = "C#语言",
Vocation = Vocation.Programmer
},
new Teacher()
{
Name = "王五",
Age = 29,
Sex = "男",
Subject = "数学老师",
Vocation = Vocation.Teacher
}
};
序列化无需特殊处理,直接序列化就好了:
var setting = new JsonSerializerSettings
{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
};
var json = JsonConvert.SerializeObject(list, setting);
序列化结果如下:
如果按照往常正常逻辑进行反序列化,则得到的结果如下所示,少了李四中的language成员和王五的subject成员:
var obj = JsonConvert.DeserializeObject<List<Person>>(json); // json为上图中的json字符串
重点来了,重点来了,这个时候对于上面的json字符串,如何反序列化得到完整的包含子类的list对象呢?
答:反序列化时使用 public static T DeserializeObject<[Nullable(2)] T>(string value, params JsonConverter[] converters)这个方法,即使用JsonConverter的集合将JSON反序列化为指定的.NET类型。需要创建一个Person转换器,该转换器需要继承JsonConverter,具体看代码:
public class PersonConverter : DataCreationConverter<Person>
{
protected override Person Create(JObject jObject)
{
//判断属性值(关键字)来确认是哪个子类,并创建子类
if (FieldExists("vocation", jObject, out string type))
{
switch (type)
{
case "1": return new Teacher();
case "2": return new Programmer();
default: return new Person();
}
}
else
{
return new Person();
}
}
private bool FieldExists(string fieldName, JObject jObject, out string entityName)
{
entityName = jObject[fieldName] == null ? "" : jObject[fieldName].ToString();
return jObject[fieldName] != null;
}
}
public abstract class DataCreationConverter<T> : JsonConverter
{
protected abstract T Create(JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
// 基于JObject创建目标对象
T target = Create(jObject);
// 填充对象属性
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
person转换器创建好之后,则使用该转换器反序列化json,此json为上面得到的[{"name":"张三","age":18,"sex":"男","vocation":0},{"language":"C#语言","name":"李四","age":18,"sex":"女","vocation":2},{"subject":"数学老师","name":"王五","age":29,"sex":"男","vocation":1}]:
var obj2 = JsonConvert.DeserializeObject<List<Person>>(json, new PersonConverter());
反序列化结果,得到了子集对象:
完整工程代码可免费下载:https://gitee.com/dmtlls/json-utils