Newtonsoft.Json⾼级⽤法
⼿机端应⽤讲究速度快,体验好。刚好⼿头上的⼀个项⽬服务端接⼝有性能问题,需要进⾏优化。在接⼝多次修改中,实体添加了很多字段⽤于中间计算或者存储,然后最终⽤Newtonsoft.Json进⾏序列化返回数据,经过分析⼀个简单的列表接⼝每⼀⾏数据返回了16个字段,但是⼿机APP端只⽤到了其中7个字段,剩余9个字段的数据全部都是多余的,如果接⼝返回数据为40K⼤⼩,也就是说⼤约20K的数据为⽆效数据,3G⽹络下20K下载差不多需要1s,不返回⽆效数据⾄少可以节约1s的时间,⼤⼤提⾼⽤户体验。本篇将为⼤家介绍Newtonsoft.Json的⼀些⾼级⽤法,可以修改很少的代码解决上述问题。
阅读⽬录
Newtonsoft.Json介绍
在做开发的时候,很多数据交换都是以json格式传输的。⽽使⽤Json的时候,我们很多时候会涉及到⼏个序列化对象的使⽤:DataContractJsonSerializer,JavaScriptSerializer 和即Newtonsoft.Json。⼤多数⼈都会选择性能以及通⽤性较好Json.NET,这个不是微软的类库,但是⼀个开源的世界级的Json操作类库,从下⾯的性能对⽐就可以看到它的其中之⼀的性能优点。
齐全的介绍,使⽤⽅式简单
基本⽤法
Json.Net是⽀持序列化和反序列化DataTable,DataSet,Entity Framework和Entity的。下⾯分别举例说明序列化和反序列化。DataTable:
/
/序列化DataTable
DataTable dt = new DataTable();
dt.Columns.Add("Age", Type.GetType("System.Int32"));
dt.Columns.Add("Name", Type.GetType("System.String"));
dt.Columns.Add("Sex", Type.GetType("System.String"));
dt.Columns.Add("IsMarry", Type.GetType("System.Boolean"));
for (int i = 0; i < 4; i++)
{
DataRow dr = dt.NewRow();
dr["Age"] = i + 1;
dr["Name"] = "Name" + i;
dr["Sex"] = i % 2 == 0 ? "男" : "⼥";
dr["IsMarry"] = i % 2 > 0 ? true : false;
dt.Rows.Add(dr);
}
Console.WriteLine(JsonConvert.SerializeObject(dt));
OptOut 默认值,类中所有公有成员会被序列化,如果不想被序列化,可以⽤特性JsonIgnore
OptIn 默认情况下,所有的成员不会被序列化,类中的成员只有标有特性JsonProperty 的才会被序列化,当类的成员很多,但客户端仅仅需要⼀部分数据
时,
很有⽤
利⽤上⾯字符串进⾏反序列化
string json = JsonConvert.SerializeObject(dt);
dt=JsonConvert.DeserializeObject<DataTable>(json);
foreach (DataRow dr in dt.Rows)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t", dr[0], dr[1], dr[2], dr[3]);
}
Entity 序列化和DataTable ⼀样,就不过多介绍了。
⾼级⽤法
1.忽略某些属性
2.默认值的处理
3.空值的处理
4.⽀持⾮公共成员
5.⽇期处理
6.⾃定义序列化的字段名称
7.动态决定属性是否序列化
8.枚举值的⾃定义格式化问题
9.⾃定义类型转换
10.全局序列化设置
⼀.忽略某些属性
类似本问开头介绍的接⼝优化,实体中有些属性不需要序列化返回,可以使⽤该特性。⾸先介绍Json.Net 序列化的模式:OptOut 和 OptIn
仅需要姓名属性
[JsonObject(MemberSerialization.OptIn)]
public class Person
{
public int Age { get ; set ; }
[JsonProperty]
public string Name { get ; set ; }
public string Sex { get ; set ; }
public bool IsMarry { get ; set ; }
public DateTime Birthday { get ; set ; }
}
DefaultValueHandling.Ignore 序列化和反序列化时,忽略默认值DefaultValueHandling.Include 序列化和反序列化时,
包含默认值 不需要是否结婚属性
[JsonObject(MemberSerialization.OptOut)]
public class Person
{
public int Age { get ; set ; }
public string Name { get ; set ; }
public string Sex { get ; set ; }
[JsonIgnore]
public bool IsMarry { get ; set ; }
public DateTime Birthday { get ; set ; }
}
通过上⾯的例⼦可以看到,要实现不返回某些属性的需求很简单。1.在实体类上加上[JsonObject(MemberSerialization.OptOut)] 2.在不需要返回的属性上加上 [JsonIgnore]说明。
⼆.默认值处理
序列化时想忽略默认值属性可以通过JsonSerializerSettings.DefaultValueHandling 来确定,该值为枚举值
[DefaultValue(10)]
public int Age { get ; set ; }
Person p = new Person { Age = 10, Name = "张三丰", Sex = "男", IsMarry = false , Birthday = new DateTime(1991, 1, 2) };
JsonSerializerSettings jsetting=new JsonSerializerSettings();
jsetting.DefaultValueHandling=DefaultValueHandling.Ignore;
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));
最终结果如下:
三.空值的处理
序列化时需要忽略值为NULL 的属性,可以通过JsonSerializerSettings.NullValueHandling 来确定,另外通过JsonSerializerSettings 设置属性是对序列化过程中所有属性⽣效的,想单独对某⼀个属性⽣
效可以使⽤JsonProperty ,下⾯将分别展⽰两个⽅式
1.JsonSerializerSettings
Person p = new Person { room=null ,Age = 10, Name = "张三丰", Sex = "男", IsMarry = false , Birthday = new DateTime(1991, 1, 2) };
JsonSerializerSettings jsetting=new JsonSerializerSettings();
jsetting.NullValueHandling = NullValueHandling.Ignore;
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));
2.JsonProperty
通过JsonProperty属性设置的⽅法,可以实现某⼀属性特别处理的需求,如默认值处理,空值处理,⾃定义属性名处理,格式化处理。上⾯空值处理实现
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public Room room { get; set; }
四.⽀持⾮公共成员
序列化时默认都是处理公共成员,如果需要处理⾮公共成员,就要在该成员上加特性"JsonProperty"
[JsonProperty]
private int Height { get; set; }typeof的用法
五.⽇期处理
对于Dateime类型⽇期的格式化就⽐较⿇烦了,系统⾃带的会格式化成iso⽇期标准,但是实际使⽤过程中⼤多数使⽤的可能是yyyy-MM-dd 或者yyyy-MM-dd HH:mm:ss两种格式的⽇期,解决办法是可以将DateTime类型改成string 类型⾃⼰格式化好,然后在序列化。如果不想修改代码,可以采⽤下⾯⽅案实现。
Json.Net提供了IsoDateTimeConverter⽇期转换这个类,可以通过JsnConverter实现相应的⽇期转换
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime Birthday { get; set; }
但是IsoDateTimeConverter⽇期格式不是我们想要的,我们可以继承该类实现⾃⼰的⽇期
public class ChinaDateTimeConverter : DateTimeConverterBase
{
private static IsoDateTimeConverter dtConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd" };
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return dtConverter.ReadJson(reader, objectType, existingValue, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
dtConverter.WriteJson(writer, value, serializer);
}
}
⾃⼰实现了⼀个yyyy-MM-dd格式化转换类,可以看到只是初始化IsoDateTimeConverter时给的⽇期格式为yyyy-MM-dd即可,下⾯看下效果
[JsonConverter(typeof(ChinaDateTimeConverter))]
public DateTime Birthday { get; set; }
可以根据⾃⼰需求实现不同的转换类
六.⾃定义序列化的字段名称
实体中定义的属性名可能不是⾃⼰想要的名称,但是⼜不能更改实体定义,这个时候可以⾃定义序列化字段名称。
[JsonProperty(PropertyName = "CName")]
public string Name { get; set; }
七.动态决定属性是否序列化
这个是为了实现@⽶粒⼉提的需求特别增加的,根据某些场景,可能A场景输出A,B,C三个属性,B场景输出E,F属性。虽然实际中不⼀定存在这种需求,但是json依然可以⽀持该特性。
继承默认的DefaultContractResolver类,传⼊需要输出的属性
重写修改了⼀下,⼤多数情况下应该是要排除的字段少于要保留的字段, 为了⽅便书写这⾥修改了构造函数加⼊retain表⽰props是需要保留的字段还是要排除的字段
public class LimitPropsContractResolver : DefaultContractResolver
{
string[] props = null;
bool retain;
///<summary>
///构造函数
///</summary>
///<param name="props">传⼊的属性数组</param>
///<param name="retain">true:表⽰props是需要保留的字段 false:表⽰props是要排除的字段</param>
public LimitPropsContractResolver(string[] props, bool retain=true)
{
//指定要序列化属性的清单
this.props = props;
}
protected override IList<JsonProperty> CreateProperties(Type type,
MemberSerialization memberSerialization)
{
IList<JsonProperty> list =
base.CreateProperties(type, memberSerialization);
//只保留清单有列出的属性
return list.Where(p => {
if (retain)
{
return props.Contains(p.PropertyName);
}
else
{
return !props.Contains(p.PropertyName);
}
}).ToList();
}
public int Age { get; set; }
[JsonIgnore]
public bool IsMarry { get; set; }
public string Sex { get; set; }
JsonSerializerSettings jsetting=new JsonSerializerSettings();
jsetting.ContractResolver = new LimitPropsContractResolver(new string[] { "Age", "IsMarry" });
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));
使⽤⾃定义的解析类,只输出"Age", "IsMarry"两个属性,看下最终结果.只输出了Age属性,为什么IsMarry属性没有输出呢,因为标注了JsonIgnore
看到上⾯的结果想要实现pc端序列化⼀部分,⼿机端序列化另⼀部分就很简单了吧,我们改下代码实现⼀下
string[] propNames = null;
if (p.Age > 10)
{
propNames = new string[] { "Age", "IsMarry" };
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论