JSON.NET 使用技巧
1. 序列化相关技巧
通过特性忽略某些属性
有时候我们会有这样的需求,我们只需要序列化实体类中的一部分属性,这时候我们可以通过声明忽略掉一些我们不需要序列化的属性,有两种方式可以使用么达到这个目标:
首先,可以考虑使用JsonIgnore
特性修饰不需要进行序列化的属性,如下所示:
public class EmployeeBean
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
public string Phone { get; set; }
[JsonIgnore]
public DateTime HireDate { get; set; }
}
运行程序:
var employeeBean = new EmployeeBean()
{
Id = Guid.NewGuid(),
Name = "gyzhao",
Email = "gyzhao@gyzhao.com",
Salary = 10000,
Phone = "13912390987",
HireDate = new DateTime(2012, 2, 1)
};
var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented);
//输出:
//{
// "Id": "69a406ad-902c-45d3-8ba7-89a09779ed52",
// "Name": "gyzhao",
// "Email": "gyzhao@gyzhao.com",
// "Salary": 10000.0,
// "Phone": "13912390987"
//}
如果说你需要序列化的类有很多的属性,而你是需要使用其中的一小部分,如果使用上面的上面方式就会比较繁琐(因为需要忽略的属性太多了),这时候可以考虑使用DataContract
特性修饰被序列化的类,使用DataMember
特性修饰需要进行序列化的属性,其他没有该特性属性会被自动忽略掉。如下所示:
[DataContract]
public class EmployeeBean
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public decimal Salary { get; set; }
public string Phone { get; set; }
public DateTime? HireDate { get; set; }
}
运行程序:
var employeeBean = new EmployeeBean()
{
Id = Guid.NewGuid(),
Name = "gyzhao",
Email = "gyzhao@gyzhao.com",
Salary = 10000,
Phone = "13912390987",
HireDate = new DateTime(2012, 2, 1)
};
var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented);
//输出:
//{
// "Id": "69a406ad-902c-45d3-8ba7-89a09779ed52",
// "Name": "gyzhao",
// "Email": "gyzhao@gyzhao.com",
// "Salary": 10000.0
//}
DataContract
特性和DataMember
特性都从属于:System.Runtime.Serialization
命名空间。
动态序列化对象属性
多谢园友 @夜色、花清浅 的提醒,确实有这样的场景:更多的我们可能需要的是动态的来确定需要序列化哪些属性,比如对于EmployeeBean来说:A方法需要序列化 Name
和 Id
属性,而 B方法需要序列化 Email
和 Phone
属性,在这种情况下,前面的两种使用特性的方式并不能很好的适应需求的变化,通过查询 JSON.NET 的文档(传送门:Json.NET Documentation),官方文档提供了这个API的示例程序,下面是改进的示例:
var employeeBean = new EmployeeBean()
{
Id = Guid.NewGuid(),
Name = "gyzhao",
Email = "gyzhao@gyzhao.com",
Salary = 10000,
Phone = "13912390987",
HireDate = new DateTime(2015, 5, 4)
};
var perperties = new List<string>()
{
employeeBean.GetPropertyName(t => t.Email),
employeeBean.GetPropertyName(t => t.Phone)
};
var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented, new JsonSerializerSettings()
{
ContractResolver = new JsonDynamicContractResolver(perperties)
});
//{
// "Email": "gyzhao@gyzhao.com",
// "Phone": "13912390987"
//}
Console.WriteLine(jsonString);
下面是定义 JsonDynamicContractResolver
类的定义:
public class JsonDynamicContractResolver : DefaultContractResolver
{
private readonly List<string> _propertiesList;
public JsonDynamicContractResolver(IEnumerable<string> propertiesEnumerable)
{
if (propertiesEnumerable != null)
{
_propertiesList = propertiesEnumerable.ToList();
}
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
//只序列化构造器中传入的包含在字符串中的属性
if (_propertiesList != null && _propertiesList.Any())
{
properties =
properties.Where(p => _propertiesList.Exists(pString => pString == p.PropertyName)).ToList();
}
return properties;
}
}
在 传入 JsonDynamicContractResolver
构造函数中的指定序列化属性的集合时,我在这里使用了扩展方法:GetPropertyName
,这个方法通过传入一个 Lambda
表达式来获取需要序列化属性的字符串表示,这里是通过表达式树来实现的。相对于直接硬编码属性名称的字符串来说,使用表达式树动态获取在效率上有所损失(可接受的程度),不过换取的是设计上的灵活。比如:当我们更改属性名称时,编译器可以为我们提供类型安全的保护。而如果硬编码的话,如果一旦忘记修改,那么运行就会抛出异常,特别是系统中如果有很多地方都是用这种硬编码方式的话,那么维护起来就是一个噩梦了。下面是该扩展方法的代码:
public static class Extensions
{
/// <summary>
/// 获取对象实例属性的字符串表示
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <param name="func"></param>
/// <returns></returns>
public static string GetPropertyName<T>(this T obj, Expression<Func<T, object>> func)
{
var propertyName = string.Empty;
var expression = func.Body as UnaryExpression;
if (expression != null)
{
propertyName = ((MemberExpression) expression.Operand).Member.Name;
}
else
{
var memberExpression = func.Body as MemberExpression;
if (memberExpression != null)
{
propertyName = memberExpression.Member.Name;
}
else
{
var body = func.Body as ParameterExpression;
if (body != null)
{
propertyName = body.Type.Name;
}
}
}
return propertyName;
}
}
序列化对象时循环引用异常的解决办法
序列化一个对象时,如果该对象有一个集合属性,改集合的类型就是对象本身的话,默认序列化的方法会报一个循环引用的异常,如果需要序列化,只需声明下面的属性即可:
JsonConvert.SerializeObject(result,new JsonSerializerSettings{ReferenceLoopHandling=ReferenceLoopHandling.Serialize})
2. 反序列化相关技巧
2.1 使用匿名类型作为反序列化实体
var jsonString = @"{
'Id': '69a406ad-902c-45d3-8ba7-89a09779ed52',
'Name': 'gyzhao',
'Salary': 10000.0,
'HireDate': '2012-02-01T00:00:00'
}";
var employee = new
{
Name = default(string),
Salary = default(decimal),
HireDate = default(DateTime),
Id = default(Guid)
};
var employeeBean = JsonConvert.DeserializeAnonymousType(jsonString, employee);
3. 创建JSON
//命令式的创建JSON对象
var array = new JArray();
var text = new JValue("Manual text");
var date = new JValue(DateTime.Now);
array.Add(text);
array.Add(date);
Console.WriteLine(array.ToString());
//使用声明式的语法
var rss =
new JObject(
new JProperty("channel", new JObject(
new JProperty("title", "James Nexton-king"),
new JProperty("link", "http://james.newtonking.com"),
new JProperty("description", "James Newton-Kin's blog."),
new JProperty("item", "BB"))));
Console.WriteLine(rss.ToString());
//通过一个匿名对象创建JSON
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-king",
link = "http://james.netwoing.com",
item = new List<string>()
{
"A",
"B",
"C",
"D",
"E"
}
}
});
Console.WriteLine(o.ToString());
参考&进一步阅读
http://www.newtonsoft.com/json
JSON.NET 使用技巧的更多相关文章
- [转]Golang 中使用 JSON 的小技巧
taowen是json-iterator的作者. 序列化和反序列化需要处理JSON和struct的关系,其中会用到一些技巧. 原文 Golang 中使用 JSON 的小技巧是他的经验之谈,介绍了一些s ...
- JSON 的小技巧
有的时候上游传过来的字段是string类型的,但是我们却想用变成数字来使用. 本来用一个json:",string" 就可以支持了,如果不知道golang的这些小技巧,就要大费周章 ...
- JSON 字符串解析技巧总结
在解析JSONObject的字符数据的时候,可以考虑去使用optString 解析网络JSON数据时,获取数据的两个方法optString和getString: 使用optString获取数据时,即使 ...
- python json模块小技巧
python的json模块通常用于与序列化数据,如 def get_user_info(user_id): res = {"user_id": 190013234,"ni ...
- C#操作JSON
http://www.cnblogs.com/LiZhiW/p/3624729.html C#操作JSON 1. .NET对JSON的支持介绍............................. ...
- C#操作Json(转)
原文:http://wenku.baidu.com/link?url=3dlqKdF26ZdQIAcX9jvP2ZYEtl3J0sKOV8XuHQI0Rz4SjB9S46nqmGiMXUVQa_1Pm ...
- .NET的JSON格式数据的三种转换方式
说明: 1..Net进行JSON格式的数据传递的时候,势必用到序列化和反序列化对象,总共有三种方式可是在.NET中实现序列化和反序列化的需求. 2.操作JSON的速度是:Json.net > M ...
- VS Code开发技巧集锦【转】
转自:http://blog.csdn.net/tiantangyouzui/article/details/52163175 入门 自定义 扩展 文件/文件夹管理 编辑技巧 智能感应功能 代码片段 ...
- 跟着视频做的SSH项目总结
一直没做过SSH(Struts2+Spring+Hibernate)的实际项目,只是三个框架学的还熟练,但整合起来使用就不知道了.所以前段时间在网上找了一套SSH实际项目的视频来学习(确切的说是买的. ...
随机推荐
- VMware虚拟机Mac OS X无法调整扩展硬盘大小,更新xcode时出现磁盘空间不足
使用VMware虚拟机搭建的MacOSX,安装xcode时出现磁盘空间不足的错误. 因为很多朋友在初次安装MacOSX的时候都默认选择40G的磁盘大小,结果用了没两天之后就发现磁盘不够用了. 这时,百 ...
- 探秘Tomcat(一)——Myeclipse中导入Tomcat源码
前言:有的时候自己不知道自己是井底之蛙,这并没有什么可怕的,因为你只要蜷缩在方寸之间的井里,无数次的生活轨迹无非最终归结还是一个圆形:但是可怕的是有一天你不得不从井里跳出来生活,需要重新审视井以外的生 ...
- 吐槽坑爹的微软win store app审核
从学习win store app 开发到做出第一个应用 博客园cnblogs 花了一个多月的全部业余和上班空闲时间, 上周在端午节放假期间终于完成了计划的全部开发和测试, 6月10号怀着无比激动的心情 ...
- 设计宝库:22套精美的 PhotoShop 素材免费下载
<设计宝库>系列给大家带来22套精美的 PSD 设计素材,你可以免费下载使用.设计师经常会去网上搜罗各种各样的素材,这些免费素材不仅能帮助他们节省大量的时间,而且能有很好的效果.非常感谢那 ...
- SQL Server中的事务日志管理(9/9):监控事务日志
当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会 ...
- 基于HT for Web矢量实现HTML5文件上传进度条
在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件 ...
- 基于HT的CSG功能构建HTML5的3D书架
构造实体几何CSG全称Constructive solid geometry,是3D计算机图形学中构建模型的常用技术,可通过合并Union.相减Subtraction和相交Intersction的三种 ...
- ASP.NET MVC显示HTML字符串
一些html经HtmlEncode后,如“<span>测试数据</span>”.现需要把这些内容正常显示于asp.net mvc的视图内. 举个例子来解决与说明,先创建一个mo ...
- 【工具】清理Windows Installer冗余文件(支持64位NT6.x系统)
样子: 支持系统: Windows NT 5.x/6.x 32及64位所有系统.需.net framework 2.0运行环境 功能: 清理上述系统中冗余的Windows Installer补丁文件. ...
- Windows线程漫谈界面线程和工作者线程
每个系统都有线程,而线程的最重要的作用就是并行处理,提高软件的并发率.针对界面来说,还能提高界面的响应力. 线程分为界面线程和工作者线程,界面实际就是一个线程画出来的东西,这个线程维护一个“消息队列” ...