namespace 信息采集系统.Common
{
    /// <summary>
    /// Json类型对象,用于其它Json对象继承
    /// </summary>
    /// <typeparam name="T">自定义类型</typeparam>
    [DataContract]
    public abstract class JsonObject<T>
    {
        /// <summary>
        /// 将Json对象转换为字节数组
        /// </summary>
        /// <returns></returns>
        public byte[] ToArray()
        {
            var serializer = new DataContractJsonSerializer(this.GetType());
            using (var ms = new MemoryStream())
            {
                serializer.WriteObject(ms, this);
                var b = ms.ToArray();
                return b;
            }
        }
        /// <summary>
        /// 将Json对象转换为字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var b = this.ToArray();
            var s = Encoding.UTF8.GetString(b);
            return s;
        }
        /// <summary>
        /// 将Json对象转换为字符串,并进行格式化输出
        /// </summary>
        /// <returns>利于阅读的Json字符串</returns>
        public string ToFriendlyString()
        {
            return this.toFriendlyString(this, 0);
        }
        private string toFriendlyString(object obj, int level)
        {
            var sbAll = new StringBuilder();
            var type = obj.GetType();
            var interfaces = type.GetInterfaces();
            if (interfaces.Contains(typeof(System.Collections.IList)))
            {
                var arr = obj as System.Collections.IList;
                var sbLine = new StringBuilder();
                sbLine.Append($"\r\n{makeMultiSymbol(level)}[\r\n");
                sbAll.Append(sbLine.ToString());
                for (int i = 0; i < arr.Count; i++)
                {
                    var item = arr[i];
                    string line = this.toFriendlyString(item, level + 1);
                    sbAll.Append(line);


                    if (i < arr.Count - 1)
                        sbAll.Append(",\r\n");
                    else
                        sbAll.Append("\r\n");
                }
                sbLine = new StringBuilder();
                sbLine.Append($"{makeMultiSymbol(level)}]");
                sbAll.Append(sbLine.ToString());
            }
            else
            {
                var sbLine = new StringBuilder();
                sbLine.Append($"{makeMultiSymbol(level)}{{\r\n");
                sbAll.Append(sbLine.ToString());
                var dict = new Dictionary<int, string[]>();
                var fields = type.GetFields();

                for (int i = 0; i < fields.Length; i++)
                {
                    var field = fields[i];
                    var atts = field.GetCustomAttributes(true);
                    var att = atts.FirstOrDefault(x => x is DataMemberAttribute);
                    if (att == null) continue;
                    var order = (att as DataMemberAttribute).Order;
                    var name = field.Name;
                    var value = field.GetValue(obj);
                    sbLine = new StringBuilder();
                    string strValue;
                    if (value == null)
                        strValue = "null";
                    else
                    {
                        var attrType = value.GetType();
                        if (attrType.IsEnum)
                            strValue = ((int)value).ToString();
                        else if (attrType == typeof(string))
                            strValue = StringExt.ToCodeFormat(value as string);
                        else if (attrType.IsValueType)
                            strValue = value.ToString();
                        else
                            strValue = this.toFriendlyString(value, level + 1);
                    }
                    if (dict.Values.Count(x => x[0] == name) == 0)
                    {
                        if (order == -1) order = GetNextOrderID(dict);
                        dict.Add(order, new string[] { name, strValue });
                    }
                }

                var properties = type.GetProperties();
                for (int i = 0; i < properties.Length; i++)
                {
                    var property = properties[i];
                    var atts = property.GetCustomAttributes(true);
                    var att = atts.FirstOrDefault(x => x is DataMemberAttribute);
                    if (att == null) continue;

                    var order = (att as DataMemberAttribute).Order;
                    var name = property.Name;
                    var value = property.GetValue(obj, null);
                    sbLine = new StringBuilder();
                    string strValue;
                    if (value == null)
                        strValue = "null";
                    else
                    {
                        var attrType = value.GetType();
                        if (attrType.IsEnum)
                            strValue = ((int)value).ToString();
                        else if (attrType == typeof(string))
                            strValue = StringExt.ToCodeFormat(value as string);
                        else if (attrType.IsValueType)
                            strValue = value.ToString();
                        else
                            strValue = this.toFriendlyString(value, level + 1);
                    }
                    if (dict.Values.Count(x => x[0] == name) == 0)
                    {
                        if (order == -1) order = GetNextOrderID(dict);
                        dict.Add(order, new string[] { name, strValue });
                    }
                }
                var kvs = dict.OrderBy(x => x.Key).ToArray();
                for (int i = 0; i < kvs.Length; i++)
                {
                    string line;
                    var kv = kvs[i].Value;
                    var name = kv[0];
                    var strValue = kv[1];
                    if (i < dict.Count - 1)
                        line = $"{makeMultiSymbol(level + 1)}\"{name}\":{strValue},\r\n";
                    else
                        line = $"{makeMultiSymbol(level + 1)}\"{name}\":{strValue}\r\n";
                    sbLine = new StringBuilder();
                    sbLine.Append(line);
                    sbAll.Append(sbLine.ToString());
                }
                sbLine = new StringBuilder();
                sbLine.Append($"{makeMultiSymbol(level)}}}");
                sbAll.Append(sbLine.ToString());
            }
            var result = sbAll.ToString();
            return result;
        }

        private string makeMultiSymbol(int count)
        {
            var symbol = "\t";
            var sb = new StringBuilder();
            for (int i = 0; i < count; i++)
            {
                sb.Append(symbol);
            }
            return sb.ToString();
        }
        /// <summary>
        /// 字节数组转换为Json对象
        /// </summary>
        /// <param name="b">字节数组</param>
        /// <returns>Json对象</returns>
        public static T From(byte[] b)
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream(b))
            {
                var o = (T)serializer.ReadObject(ms);
                return o;
            }
        }
        /// <summary>
        /// 字符串转换为Json对象
        /// </summary>
        /// <param name="s">字符串</param>
        /// <returns>Json对象</returns>
        public static T Parse(string s)
        {
            var b = Encoding.UTF8.GetBytes(s);
            var obj = From(b);
            return obj;
        }
        /// <summary>
        /// 将Json对象存储为文件
        /// </summary>
        /// <param name="filePath">保存文件名</param>
        /// <param name="friendlyFormat"></param>
        public void Write(string filePath, bool friendlyFormat = false)
        {
            if (File.Exists(filePath)) File.Delete(filePath);
            if (friendlyFormat)
            {
                var s = this.ToFriendlyString();
                File.WriteAllText(filePath, s);
            }
            else
            {
                var b = this.ToArray();
                File.WriteAllBytes(filePath, b);
            }
        }
        /// <summary>
        /// 读取指定文件,加载Json对象
        /// </summary>
        /// <param name="filePath">Json文件路径</param>
        /// <returns>Json对象</returns>
        public static T Read(string filePath)
        {
            var s = File.ReadAllText(filePath);
            var obj = JsonObject<T>.Parse(s);
            return obj;
        }
        /// <summary>
        /// 获取下一个可用的OrderID
        /// </summary>
        /// <param name="dict">临时存储节点的字典对象</param>
        /// <returns>下一个可用的OrderID</returns>
        public int GetNextOrderID(Dictionary<int, string[]> dict)
        {
            int order = 0;
            bool unused = false;
            while (!unused)
            {
                var exist = dict.Keys.Any(x => x == order);
                if (!exist)
                {
                    unused = true;
                }
                else
                {
                    order += 1;
                }
            }
            return order;
        }

    }
    /// <summary>
    /// 字符串扩展
    /// </summary>
    public static class StringExt
    {
        /// <summary>
        /// 将字符串转换成带转义符的形式
        /// </summary>
        /// <param name="s">输入字符串</param>
        /// <returns></returns>
        public static string ToCodeFormat(this string s)
        {
            s = s.Replace("\\", "\\\\");
            s = s.Replace("\b", "\\b");
            s = s.Replace("\f", "\\f");
            s = s.Replace("\n", "\\n");
            s = s.Replace("\r", "\\r");
            s = s.Replace("\'", "\\'");
            s = s.Replace("\"", "\\\"");
            s = s.Replace("\t", "\\t");
            s = s.Replace("\0", "\\0");
            s = s.Replace("\a", "\\a");
            s = s.Replace("\v", "\\v");
            return $"\"{s}\"";
        }
    }
}
posted on 2019-12-20 09:16  幸福的老田  阅读(223)  评论(0编辑  收藏  举报