Unity自己的Json序列化是不支持字典格式的,而且功能比较单一,这里介绍一个.Net中开源的Json序列化和反序列化库和基本用法以及常用的数据处理方法(github地址:https://github.com/JamesNK/Newtonsoft.Json/releases )(百度网盘:链接:https://pan.baidu.com/s/1S4cQW3NoU-g5AMPZ8VKzvQ 提取码:b19e ),
这里的接口包含数据序列化反序列化两个方法,因为可能会碰到Json,Xml,二进制或者其他的结构。
public interface IObjectSerializer
{
string Serializer(T obj);
T DeSerializer(string content);
}
数据处理时我们可以设置 JsonSerializerSettings ,在数据处理时字段名转换为驼峰命名法,(比如我们客户端用的是大驼峰法,Java服务器习惯用的小驼峰法)也就是说当我们客户端的代码为 pubilc string Name = "Alice";时,经过序列化后的字符串后会变为 "name"="Alice",而不是"Name" = "Alice";
ContractResolver = new CamelCasePropertyNamesContractResolver()对 JSON 数据使用混合大小写。驼峰式,但是是javascript 首字母小写形式.
当然我们也可以继承DefaultContractResolver,重写ResolveContract方法去处理其他格式的字段名比如说字段名全小写,或者去除字段下划线。
另外这里序列化的类可以使用单利模式处理,这里因为要另外上传单利模板类,为了方便大家直接拿到可以使用,我就不再麻烦写了。
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class JsonObjectSerializer : IObjectSerializer
{
private readonly JsonSerializerSettings settings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() };
public T DeSerializer(string content)
{
if (typeof(T)==typeof(string))
{
return (T)(object)content;
}
else
{
return JsonConvert.DeserializeObject(content);
}
}
public string Serializer(T obj)
{
return JsonConvert.SerializeObject(obj, this.settings);
}
}
当我们反序列化中碰到不可为空的数据类型,而传过来的json中值是null时,会出现反序列化失败比如说Java中的包装类型 int number =null,如果我们C#中直接用 int number; 去接这个数据时就会出错,当然我们也可以提前设置为可空类型的int,int? number = null;或者 Nullable
也可以用下面这种实现JsonConVerter方法来处理
[JsonConverter(typeof(ValueTypeNullToDefaultConverter))]
public long Id { get; set; }
当接收到的是 { "Id" = null } 会序列化为 long类型的默认值 0 Id = 0;
using Newtonsoft.Json;
using System;
using UnityEngine;
public class ValueTypeNullToDefaultConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsValueType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
{
return Activator.CreateInstance(objectType);
}
return this.ChangeType(reader.Value, objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value == null ? null : value.ToString());
}
public object ChangeType(object value, Type objectType)
{
if (value == null)
{
return null;
}
try
{
return Convert.ChangeType(value, objectType);
}
catch (Exception ex)
{
Debug.LogError(string.Format("[ChangeType]:Failed to change object value '{0}' to object type '{1}',Exception:{2}", value, objectType.Name,ex));
return null;
}
}
}
DateTime类型系统自带的会格式化成iso日期标准"UpdateTime" = "2019-03-31T00:00:00",但是实际使用过程中我们可能要的是yyyy-MM-dd或者yyyy-MM-dd HH:mm:ss,或者是传给后台的减去自己所在时区的毫秒数,或者后台传回来的毫秒数要加上自己当前时区的毫秒数,这里给出的后一种的解决办法。
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
public class UnixDateTimeConverter : DateTimeConverterBase
{
public static readonly DateTime BaseTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static readonly DateTime StartTime = TimeZone.CurrentTimeZone.ToLocalTime(BaseTime);//当地时区
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value ==null)
{
return null;
}
return BaseTime.AddMilliseconds((long)reader.Value).ToLocalTime();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value!=null)
{
var dateTime = (DateTime)value;
writer.WriteRawValue(((long)(dateTime - StartTime).TotalMilliseconds).ToString());
}
}
}
一般情况下枚举值的序列化会自动格式化成枚举对应的整型数值,比如说:
pubilce enum Gender
{
Male = 0,
Female = 1,
Unknown
}
public Gender Gender = Male;
序列化后为:{"Gender:0"}
只要在 Gender属性上机上JsonConverter(typeof(StringEnumConverter))表示将枚举值转换成对应的字符串,而StringEnumConverter是Newtonsoft.Json内置的转换类型。最终输出结果 {"Gender" = "Male"}
当我们遇到接口优化,实体中有些属性不需要序列化返回,可以用该特性,比如说我们在一个实体类中有10个字段,但其中有一个属性序列化后会占用大量的字节,并且这个属性服务器是不需要的,仅供我们客户端逻辑使用。如果这些数据都上传到服务器,会造成带宽的占用,也就是说40K的数据中,会有20K的无效数据,我们要做的就是优化掉这些无效的数据。
OptOut | 默认值,类中所有公有成员会被序列化,如果不想被序列化,可以用特性JsonIgnore |
OptIn | 默认情况下,所有的成员不会被序列化,类中的成员只有标有特性JsonProperty的才会被序列化,当类的成员很多,但客户端仅仅需要一部分数据时,很有用 |
[JsonObject(MemberSerialization.OptIn)]
public class UserInfo
{
[JsonProperty]
pubilc string Name { get;set; }
pubilc int Age { get;set; }
}
序列化输出 { "Name" = "Alice" } 只输出姓名字段
[JsonObject(MemberSerialization.OptOut)]
public class Person
{
public int Age { get; set; }
[JsonIgnore]
public string Name { get; set; }
}
序列化输出为{ "Age" = "18" },忽略姓名字段
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
public class UserInfo
{
[JsonConverter(typeof(ValueTypeNullToDefaultConverter))]
public long Id { get; set; }
[JsonProperty("name")]//将json中的name反序列化时转为UserName
public string UserName { get; set; }
[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime Birthday { get; set; }
[JsonProperty(ItemConverterType =typeof(UnixDateTimeConverter))]
public List LoginTime { get; set; }
}