Newtonsoft.Json 源码地址:https://github.com/JamesNK/Newtonsoft.Json
作者James Newton-King,现在在微软工作,所以你看.NetCore有些对象映射以及System.Text.Json的方法和用法都是一毛一样的。
从组织一栏,也能看出来,他服务的团队,跟我们用的技术息息相关。
我们先看下我们之前的封装,都干了啥
public static class SerializerHelper { /// <summary> /// JSON序列化 /// </summary> /// <param name="obj">对象</param> /// <returns>JSON字符串</returns> public static string SerializeObject(this object obj) { try { var jsonSerializerSettings = new JsonSerializerSettings { DateFormatString = "yyyy-MM-dd HH:mm:ss" }; return JsonConvert.SerializeObject(obj, jsonSerializerSettings); } catch { return string.Empty; } } /// <summary> /// 反序列化 /// </summary> /// <typeparam name="T">对象</typeparam> /// <param name="json">JSON字符串</param> /// <returns>对象</returns> public static T DeserializeObject<T>(this string json) { try { return JsonConvert.DeserializeObject<T>(json); } catch { return default(T); } } /// <summary> /// 反序列化 /// </summary> /// <param name="json">JSON字符串</param> /// <returns>对象</returns> public static dynamic DeserializeObject(this string json) { try { return JsonConvert.DeserializeObject(json); } catch { return null; } } /// <summary> /// XML序列化方式深复制 /// </summary> /// <typeparam name="T">类型</typeparam> /// <param name="obj">对象</param> /// <returns>复制对象</returns> public static T DeepCopy<T>(this T obj) { object retval; using (MemoryStream ms = new MemoryStream()) { XmlSerializer xml = new XmlSerializer(typeof(T)); xml.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); retval = xml.Deserialize(ms); ms.Close(); } return (T)retval; } /// <summary> /// 将一个实体对象转换为另一个实体对象 /// </summary> /// <typeparam name="T1">第一个实体对象</typeparam> /// <typeparam name="T2">第二个实体对象</typeparam> /// <param name="source">转换的实体对象</param> /// <returns></returns> public static T2 CopyToModel<T1, T2>(T1 source) { T2 model = default(T2); if (source == null) { return model; } PropertyInfo[] pi = typeof(T2).GetProperties(); PropertyInfo[] pi1 = typeof(T1).GetProperties(); model = Activator.CreateInstance<T2>(); for (int i = 0; i < pi.Length; i++) { for (int j = 0; j < pi1.Length; j++) { if (pi[i].Name == pi1[j].Name) { pi[i].SetValue(model, pi1[j].GetValue(source, null), null); } } } return model; } /// <summary> /// 将一个实体对象转换为另一个实体对象 /// </summary> /// <typeparam name="T1">第一个实体对象</typeparam> /// <typeparam name="T2">第二个实体对象</typeparam> /// <param name="source">转换的实体对象</param> /// <returns></returns> public static List<T2> CopyToModel<T1, T2>(List<T1> source) { List<T2> modelList = new List<T2>(); if (!source.Any()) { return modelList; } PropertyInfo[] pi = typeof(T2).GetProperties(); PropertyInfo[] pi1 = typeof(T1).GetProperties(); foreach (T1 obj in source) { T2 model = Activator.CreateInstance<T2>(); for (int i = 0; i < pi.Length; i++) { for (int j = 0; j < pi1.Length; j++) { if (pi[i].Name == pi1[j].Name) { pi[i].SetValue(model, pi1[j].GetValue(obj, null), null); } } } modelList.Add(model); } return modelList; } }
这个类其实满足了我们平时大部分需求,但是在.NetCore中,很多东西被封装到了底层,由对象映射直接处理,不需要我们写这些方法了,由System.Test.Json提供支持。
这个类针对的都是string格式和对象中的类型能对应的情况。
接下来说几个不满足的:
1、json字符串中是时间戳,但是实体类中类型是DateTime
2、json字符串中是“41.0”,但是实体类中是Int
3、再比如Mongodb中的那一堆类型,没有能直接操作的,都需要转换后才能使用,比如ObjectId、Decimal128
细看这几个类型,其实还是有那么点联系的,“41.0”首先是字符串,其次更加接近浮点数,最后才是整数;ObjectId其实是UUID的格式,对应的就是一串字符串;Decimal128对应的就是Decimal。
我以第一个时间戳字符串反序列化DateTime为例。
1、先定义自定义转换器
public class DateTimeConverter : JsonConverter { /// <summary> ///转json字符串 /// </summary> /// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param> /// <param name="value">The value.</param> /// <param name="serializer">The calling serializer.</param> public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } /// <summary> ///字符串转对象 /// </summary> /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param> /// <param name="objectType">Type of the object.</param> /// <param name="existingValue">The existing value of object being read.</param> /// <param name="serializer">The calling serializer.</param> /// <returns> /// The object value. /// </returns> public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { try { JToken token = JToken.Load(reader); string time = token.ToObject<string>(); DateTime dt; if (time.Length <= 13) { dt = ConvertStringToDateTime(time); } else { dt = Convert.ToDateTime(time); } return dt; } catch { return DateTime.MinValue; } } /// <summary> /// Determines whether this instance can convert the specified object type. /// </summary> /// <param name="objectType">Type of the object.</param> /// <returns> /// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>. /// </returns> public override bool CanConvert(Type objectType) { return (objectType == typeof(DateTime)); } /// <summary> /// 将c# DateTime时间格式转换为Unix时间戳格式 /// </summary> /// <param name="time">时间</param> /// <returns>long</returns> public static long ConvertDateTimeToInt(System.DateTime time) { System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0)); long t = (time.Ticks - startTime.Ticks) / 10000; //除10000调整为13位 return t; } /// <summary> /// 时间戳转C#时间 /// </summary> /// <param name="timeStamp">The time stamp.</param> /// <returns></returns> public static DateTime ConvertStringToDateTime(string timeStamp) { DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); long lTime = long.Parse(timeStamp + "0000"); TimeSpan toNow = new TimeSpan(lTime); return dtStart.Add(toNow); } }
这个转换器中,以下方法是必须要有的:
1、WriteJson:序列化时使用(对象转JSON字符串)
2、ReadJson:反序列化时使用(JSON字符串转对象)
3、CanConvert:确定转换器实例是否可以转换指定的对象类型
所以我们要实现时间戳字符串转DataTime,只需要着重于ReadJson方法的重写。
实体类中加个特性,如下:
public class UserInfo { /// <summary> /// Gets or sets the name of the user. /// </summary> public string UserName { get; set; } /// <summary> /// Gets or sets the create time. /// </summary> [JsonConverter(typeof(DateTimeConverter))] public DateTime CreateTime { get; set; } }
可以看到我将字符串取到之后,判断了长度是否为时间戳,然后转换之后返回的。
使用如下:
string str = "{\"UserName\":\"123\",\"CreateTime\":\"1592542123500\"}"; UserInfo item = str.DeserializeObject<UserInfo>(); str = item.SerializeObject(); UserInfo item2 = str.DeserializeObject<UserInfo>(); Console.WriteLine(item2.SerializeObject());
如果想DateTime能还原回时间戳,修改一下WriteJson方法即可。
如果遇到其他情况,做法差不多,都是取到源字符串,用自己的方法进行处理即可。
留下您的脚步
最近评论