"特性"解决Entity和JSON之间因类型不一致导致转换失败问题

在项目开发的时候经常会遇到实体类和JSON之间的(反)序列化,常规操作是先定义好一个实体类,JSON格式是

{
"department": [1, 2]
},实体类定义成 public int[] department{get;set;},然后JsonConvert.DeserializeObject(json)和JsonConvert.SerializeObject(object),这是常规操作。
非常规下的是实体类对应了数据表,举个栗子SQLServer里字段不能存储int[],一般会定义成varchar(xx),然后把数组转成“1,2”字符串形式存储,取出表数据成实体类是public string department,但是序列化成JSON是[1,2]。(要是遇到太复杂的JSON是否可以直接把JSON存储到芒果里)这种情况可以通过在实体类中需要转换成数组的属性上加自定义特性解决,以下是我企业微信开发时 [JSON-->实体类-->ORM-->Database][Database-->ORM-->实体类-->JSON]对于部门字段为数组的解决方法。

新建一个ChangeTypeAttribute.cs类,中文意思是转换类型的特性,自定义特性有两个参数,一个是源类型,一个是目标类型,源类型是存储在表字段中的类型,为string,目标类型是实体类转换成JSON字段的类型,为int[]。需求定义好后开始写自定义特性:

[AttributeUsage(AttributeTargets.All)]
public class ChangeTypeAttribute:Attribute
{
    private Type sourceType;
    private Type targetType;
    public ChangeTypeAttribute(Type sourceType, Type targetType)
    {
        this.sourceType = sourceType;
        this.targetType = targetType;
    }

    public virtual Type SourceType
    {
        get { return sourceType; }
    }

    public virtual Type TargetType
    {
        get { return targetType; }
    }
}    

这个特性是用来标注在属性上的,在实体类中对应的department属性上这么写

[ChangeType(typeof(string),typeof(int[]))]
[Required]
[StringLength(500)]
public string department { getset; }


然后我们在转换的时候不用JsonConvert.DeserializeObject,而是在这个方法上面包个皮,写一个JSONTranfer.cs类,给序列化成JSON的方法包下面这个皮

public static string TranferJson<T>(T obj, string DateTimeFormats = "yyyy-MM-dd HH:mm:ss")
{
    var timeConverter = new IsoDateTimeConverter { DateTimeFormat = DateTimeFormats };
    string postData = JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter);
    //获取ChangeType特性,改变json内容
    PropertyInfo[] propertys = typeof(T).GetProperties();
    if (propertys != null && propertys.Length > 0)
    {
        foreach (PropertyInfo p in propertys)
        {
            object[] objAttrs = p.GetCustomAttributes(typeof(ChangeTypeAttribute), true);//获取自定义特性  
            if (objAttrs != null && objAttrs.Length > 0)
            {
                ChangeTypeAttribute attr = objAttrs[0as ChangeTypeAttribute;
                postData = DealObjectToJson(attr.SourceType, attr.TargetType, p.Name, postData);
            }
        };
    }
    return postData;
}

/// <summary>
/// 对象转成json时根据 源类型 和 目标类型 找到节点转换
/// </summary>
/// <param name="sourceType">实体属性类型</param>
/// <param name="targetType">JSON节点类型</param>
/// <param name="nodeName">节点</param>
/// <param name="json">源JSON</param>
/// <returns></returns>
private static string DealObjectToJson(Type sourceType, Type targetType, string nodeName, string json)
{
    if (sourceType == typeof(string) && targetType == typeof(int[]))
    {
        string content = JObject.Parse(json).SelectToken(nodeName).ToString();
        string[] tmp = content.Split(',');
        int[] iNums = Array.ConvertAll(tmp, int.Parse);
        JArray array = JArray.FromObject(iNums);
        JObject tokenselect = JObject.Parse(json);
        tokenselect[nodeName] = array;
        json = tokenselect.ToString();
    }
    else
    {
        ;
    }
    return json;
}

以后在序列化实体的时候直接JSONTranfer.TranferJson(object)就可以得到正确类型的JSON。
JSON反序列化成Object也要正确,也就是int[]-->string也要正确,代码如下:

public static T TranferObject<T>(string json)
{
    return AnalyzeResult<T>(json);
}

private static T AnalyzeResult<T>(string resultJson)
{
    T result = default(T);
    if (string.IsNullOrEmpty(resultJson) == false)
    {
        //先抓换json内容,再转换成类
        string json = resultJson;
        PropertyInfo[] propertys = typeof(T).GetProperties();
        if (propertys != null && propertys.Length > 0)
        {
            foreach (PropertyInfo p in propertys)
            {
                object[] objAttrs = p.GetCustomAttributes(typeof(ChangeTypeAttribute), true);
                if (objAttrs != null && objAttrs.Length > 0)
                {
                    ChangeTypeAttribute attr = objAttrs[0as ChangeTypeAttribute;
                    json = DealJsonToObject(attr.SourceType, attr.TargetType, p.Name, json);
                }
            };
        }

        result = JsonConvert.DeserializeObject<T>(json);
    }
    return result;
}

/// <summary>
/// json转换成对象时根据 源类型和目标类型 将json对应的节点值转换成源类型值
/// </summary>
/// <param name="sourceType">实体属性类型</param>
/// <param name="targetType">JSON节点类型</param>
/// <param name="nodeName">节点</param>
/// <param name="json">源JSON</param>
/// <returns></returns>
private static string DealJsonToObject(Type sourceType, Type targetType, string nodeName, string json)
{
    if (sourceType == typeof(string) && targetType == typeof(int[]))
    {
        JToken content = JObject.Parse(json).SelectToken(nodeName);
        int[] iNums = (int[])content.ToObject(typeof(int[]));
        string value = string.Join(",", iNums.ToArray());
        JObject tokenselect = JObject.Parse(json);
        tokenselect[nodeName] = value;
        json = tokenselect.ToString();
    }
    return json;
}

上面的方法适用于单层的JSON转换,如果遇到多层时,需要先JArray jArray = JArray.Parse(json);再遍历jArray.Children()。

如果是简单的类型互转,例如bool,int和string的互转,其实用JsonConvert的特性就可以解决,继承JsonConverter,然后重写ReadJson和WriteJson两个方法,这种网上一搜一大堆,
就酱。
~~好耐都无写公众号了~.~

 

posted @ 2018-07-14 13:33  银河Blog  阅读(1009)  评论(0)    收藏  举报