using Newtonsoft.Json;
using SqlSugar;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Data;
using System.Globalization;
using System.Numerics;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace ServiceCenter.Extensions
{
    /// <summary>
    /// 类型转换扩展
    /// </summary>
    public static class TypeExtension
    {
        /// <summary>
        /// 将字符串转换为short
        /// </summary>
        /// <param name="value">需要转换的字符串</param>
        /// <returns></returns>
        public static short ToShort(this string value)
        {
            return Convert.ToInt16(value);
        }

        /// <summary>
        /// 将int转换为short
        /// </summary>
        /// <param name="value">需要转换的字符串</param>
        /// <returns></returns>
        public static short ToShort(this int value)
        {
            return Convert.ToInt16(value);
        }

        /// <summary>
        /// 将decimal转换为short
        /// </summary>
        /// <param name="value">需要转换的字符串</param>
        /// <returns></returns>
        public static short ToShort(this decimal value)
        {
            return Convert.ToInt16(value);
        }

        /// <summary>
        /// 将字符串转换为int
        /// </summary>
        /// <param name="value">需要转换的字符串</param>
        /// <returns></returns>
        public static int ToInt(this string value)
        {
            return Convert.ToInt32(value);
        }

        /// <summary>
        ///  获取最后一位数字
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static int GetLastDigit(this string value)
        {
            return Convert.ToInt32(Regex.Match(value, @"\d+$").Value);
        }

        /// <summary>
        /// 判断值为奇数/偶数
        /// </summary>
        /// <param name="value">需要判断的值</param>
        /// <returns> true:是奇数   false:是偶数</returns>
        public static bool OddNumberOrEven(this short value)
        {
            return value % 2 != 0;
        }

        /// <summary>
        /// 获取short类型Code，只限设备组
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static short GetShortCode(this string value)
        {
            return value.Replace("G", "").ToShort();
        }

        /// <summary>
        /// 扩展方法，获得枚举的Description
        /// </summary>
        /// <param name="value">枚举值</param>
        /// <param name="nameInstead">当枚举值没有定义DescriptionAttribute，是否使用枚举名代替，默认是使用</param>
        /// <returns>枚举的Description</returns>
        public static string GetDescription(this Enum value, Boolean nameInstead = true)
        {
            Type type = value.GetType();
            string name = Enum.GetName(type, value);
            if (name == null)
            {
                return null;
            }

            FieldInfo field = type.GetField(name);
            DescriptionAttribute attribute = System.Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;

            if (attribute == null && nameInstead == true)
            {
                return name;
            }
            return attribute?.Description;
        }

        /// <summary>
        /// 获取属性的描述信息
        /// </summary>
        public static string GetDescription(this Type type, string proName)
        {
            PropertyInfo pro = type.GetProperty(proName);
            string des = proName;
            if (pro != null)
            {
                des = pro.GetDescription();
            }
            return des;
        }

        public static string JsonToString(this object value)
        {
            return JsonConvert.SerializeObject(value);
        }

        /// <summary>
        /// 获取属性的描述信息
        /// </summary>
        public static string GetDescription(this MemberInfo info)
        {
            var attrs = (DescriptionAttribute[])info.GetCustomAttributes(typeof(DescriptionAttribute), false);
            string des = info.Name;
            foreach (DescriptionAttribute attr in attrs)
            {
                des = attr.Description;
            }
            return des;
        }

        /// <summary>
        /// 数据映射
        /// </summary>
        /// <typeparam name="D">映射目标实体Type</typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="s"></param>
        /// <returns></returns>
        public static D Mapper<D, S>(this S s)
        {
            var d = Activator.CreateInstance<D>();

            var sType = s?.GetType();
            var dType = typeof(D);

            foreach (var sP in sType.GetProperties())
            {
                foreach (var dP in dType.GetProperties())
                {
                    if (dP.Name == sP.Name)
                    {
                        dP.SetValue(d, sP.GetValue(s));
                        break;
                    }
                }
            }

            return d;
        }


        public static object Copy(this object obj, object type)
        {
            foreach (var p in type.GetType().GetProperties())
            {
                var p2 = obj.GetType().GetProperty(p.Name);
                if (p2 != null && p2.PropertyType == p.PropertyType)
                {
                    var a = p2.GetValue(obj);
                    p.SetValue(type, p2.GetValue(obj));
                }
            }
            return type;
        }

        public static object Copy(this object obj, Type type)
        {
            var res = Activator.CreateInstance(type);
            foreach (var p in type.GetProperties())
            {
                var p2 = obj.GetType().GetProperty(p.Name);
                if (p2 != null)
                {
                    var value = p2.GetValue(obj);
                    p.SetValue(res, value);
                }
            }
            return res;
        }


        //public static object Copy(this object source, Type t)
        //{
        //    var obj = Activator.CreateInstance(t);
        //    foreach (var p in t.GetProperties())
        //    {
        //        var p2 = source.GetType().GetProperty(p.Name);
        //        var value = p2.GetValue(source);
        //        p.SetValue(obj, value);
        //    }
        //    return obj;
        //}

        /// <summary>
        /// 获取字典
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="t3"></param>
        /// <returns></returns>
        public static Dictionary<string, object> EntityClassToDictionary<T>(T t)
        {
            var type = typeof(SugarColumn);
            Dictionary<string, object> d = new Dictionary<string, object>();

            var sType = t.GetType();
            foreach (var sP in sType.GetProperties())
            {
                if (sP.CustomAttributes.Any(v => v.AttributeType == type) && sP.Name != "VER" && sP.Name != "ID")
                {
                    d.Add(sP.Name, sP.GetValue(t));
                }
            }

            return d;
        }

        /// <summary>
        /// 获取MD5字符串
        /// </summary>
        /// <param name="myString"></param>
        /// <returns></returns>
        public static string GetMD5(this string myString)
        {
            var md5 = MD5.Create();
            var fromData = Encoding.Unicode.GetBytes(myString);
            var targetData = md5.ComputeHash(fromData);
            string byte2String = null;

            for (var i = 0; i < targetData.Length; i++)
            {
                byte2String += targetData[i].ToString("x");
            }

            return byte2String;
        }

        /// <summary>
        /// DataTable转换成实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<object> TableToEntity(this DataTable dt, string typeName)
        {
            var list = new List<object>();
            try
            {
                foreach (DataRow row in dt.Rows)
                {
                    var entity = Type.GetType(typeName);
                    PropertyInfo[] pArray = entity.GetType().GetProperties();

                    foreach (var p in pArray)
                    {
                        if (dt.Columns.Contains(p.Name))
                        {
                            if (!p.CanWrite) continue;
                            var value = row[p.Name];
                            if (value != DBNull.Value)
                            {
                                var targetType = p.PropertyType;
                                var convertType = targetType;
                                if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                                {
                                    //可空类型
                                    var nullableConverter = new NullableConverter(targetType);
                                    convertType = nullableConverter.UnderlyingType;
                                }
                                if (!string.IsNullOrEmpty(convertType.FullName) && !string.IsNullOrEmpty(value.ToString()))
                                {
                                    value = Convert.ChangeType(value, convertType);
                                }
                                switch (convertType.FullName)
                                {
                                    case "System.Decimal":
                                        p.SetValue(entity, Convert.ToDecimal(value), null);
                                        break;

                                    case "System.String":
                                        p.SetValue(entity, Convert.ToString(value), null);
                                        break;

                                    case "System.Int32":
                                        p.SetValue(entity, Convert.ToInt32(value), null);
                                        break;

                                    case "System.Int64":
                                        p.SetValue(entity, Convert.ToInt64(value), null);
                                        break;

                                    case "System.Int16":
                                        p.SetValue(entity, Convert.ToInt16(value), null);
                                        break;

                                    case "System.Double":
                                        p.SetValue(entity, Convert.ToDouble(value), null);
                                        break;

                                    case "System.Single":
                                        p.SetValue(entity, Convert.ToSingle(value), null);
                                        break;

                                    case "System.DateTime":
                                        p.SetValue(entity, Convert.ToDateTime(value), null);
                                        break;

                                    default:
                                        p.SetValue(entity, value, null);
                                        break;
                                }
                            }
                        }
                    }
                    list.Add(entity);
                }
            }
            catch (Exception ex)
            {
            }
            return list;
        }

        /// <summary>
        /// 转换到目标类型
        /// </summary>
        /// <param name="value"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        internal static T ConvertTo<T>(this object value) => (T)typeof(T).FromObject(value);

        public static string yyyy(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyy);
        }

        public static string yyyyMM(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMM);
        }

        public static string yyyyMMdd(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMMdd);
        }

        public static string yyyyMMddhh(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMMddhh);
        }

        public static string yyyyMMddhhmm(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMMddhhmm);
        }

        public static string yyyyMMddhhmmss(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMMddhhmmss);
        }

        public static string yyyyMMddhhmmssf(this DateTime time)
        {
            return time.GetFormat(GetFormatterEnum.yyyyMMddhhmmssfffffff);
        }

        /// <summary>
        ///  获取指定格式时间的字符串
        /// </summary>
        /// <param name="time">时间</param>
        /// <param name="formatterEnum">类型</param>
        /// <returns></returns>
        public static string GetFormat(this DateTime time, GetFormatterEnum formatterEnum)
        {
            switch (formatterEnum)
            {
                case GetFormatterEnum.Default:
                    return time.ToString();

                case GetFormatterEnum.yyyy:
                    return time.ToString("yyyy");

                case GetFormatterEnum.yyyyMM:
                    return time.ToString("yyyy-MM");

                case GetFormatterEnum.yyyyMMdd:
                    return time.ToString("yyyy-MM-dd");

                case GetFormatterEnum.yyyyMMddhh:
                    return time.ToString("yyyy-MM-dd HH");

                case GetFormatterEnum.yyyyMMddhhmm:
                    return time.ToString("yyyy-MM-dd HH:mm");

                case GetFormatterEnum.yyyyMMddhhmmss:
                    return time.ToString("yyyy-MM-dd HH:mm:ss");

                case GetFormatterEnum.yyyyMMddhhmmssfffffff:
                    return time.ToString("yyyy-MM-dd HH:mm:ss:fffffff");

                case GetFormatterEnum.only:
                    return time.ToString("yyyyMMddHHmmssfffffff");

                default:
                    return time.ToString();
            }
        }

        private static ConcurrentDictionary<Type, Func<string, object>> _dicFromObject = new ConcurrentDictionary<Type, Func<string, object>>();

        public static object FromObject(this Type targetType, object value, Encoding encoding = null)
        {
            if (targetType == typeof(object)) return value;
            if (encoding == null) encoding = Encoding.UTF8;
            var valueIsNull = value == null;
            var valueType = valueIsNull ? typeof(string) : value.GetType();
            if (valueType == targetType) return value;
            if (valueType == typeof(byte[])) //byte[] -> guid
            {
                if (targetType == typeof(Guid))
                {
                    var bytes = value as byte[];
                    return Guid.TryParse(BitConverter.ToString(bytes, 0, Math.Min(bytes.Length, 36)).Replace("-", ""), out var tryguid) ? tryguid : Guid.Empty;
                }
                if (targetType == typeof(Guid?))
                {
                    var bytes = value as byte[];
                    return Guid.TryParse(BitConverter.ToString(bytes, 0, Math.Min(bytes.Length, 36)).Replace("-", ""), out var tryguid) ? (Guid?)tryguid : null;
                }
            }
            if (targetType == typeof(byte[])) //guid -> byte[]
            {
                if (valueIsNull) return null;
                if (valueType == typeof(Guid) || valueType == typeof(Guid?))
                {
                    var bytes = new byte[16];
                    var guidN = ((Guid)value).ToString("N");
                    for (var a = 0; a < guidN.Length; a += 2)
                        bytes[a / 2] = byte.Parse($"{guidN[a]}{guidN[a + 1]}", NumberStyles.HexNumber);
                    return bytes;
                }
                return encoding.GetBytes(value.ToInvariantCultureToString());
            }
            else if (targetType.IsArray)
            {
                if (value is Array valueArr)
                {
                    var targetElementType = targetType.GetElementType();
                    var sourceArrLen = valueArr.Length;
                    var target = Array.CreateInstance(targetElementType, sourceArrLen);
                    for (var a = 0; a < sourceArrLen; a++) target.SetValue(targetElementType.FromObject(valueArr.GetValue(a), encoding), a);
                    return target;
                }
                //if (value is IList valueList)
                //{
                //    var targetElementType = targetType.GetElementType();
                //    var sourceArrLen = valueList.Count;
                //    var target = Array.CreateInstance(targetElementType, sourceArrLen);
                //    for (var a = 0; a < sourceArrLen; a++) target.SetValue(targetElementType.FromObject(valueList[a], encoding), a);
                //    return target;
                //}
            }
            var func = _dicFromObject.GetOrAdd(targetType, tt =>
            {
                if (tt == typeof(object)) return vs => vs;
                if (tt == typeof(string)) return vs => vs;
                if (tt == typeof(char[])) return vs => vs == null ? null : vs.ToCharArray();
                if (tt == typeof(char)) return vs => vs == null ? default(char) : vs.ToCharArray(0, 1).FirstOrDefault();
                if (tt == typeof(bool)) return vs =>
                {
                    if (vs == null) return false;
                    switch (vs.ToLower())
                    {
                        case "true":
                        case "1":
                            return true;
                    }
                    return false;
                };
                if (tt == typeof(bool?)) return vs =>
                {
                    if (vs == null) return false;
                    switch (vs.ToLower())
                    {
                        case "true":
                        case "1":
                            return true;

                        case "false":
                        case "0":
                            return false;
                    }
                    return null;
                };
                if (tt == typeof(byte)) return vs => vs == null ? 0 : byte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(byte?)) return vs => vs == null ? null : byte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (byte?)tryval : null;
                if (tt == typeof(decimal)) return vs => vs == null ? 0 : decimal.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(decimal?)) return vs => vs == null ? null : decimal.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (decimal?)tryval : null;
                if (tt == typeof(double)) return vs => vs == null ? 0 : double.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(double?)) return vs => vs == null ? null : double.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (double?)tryval : null;
                if (tt == typeof(float)) return vs => vs == null ? 0 : float.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(float?)) return vs => vs == null ? null : float.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (float?)tryval : null;
                if (tt == typeof(int)) return vs => vs == null ? 0 : int.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(int?)) return vs => vs == null ? null : int.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (int?)tryval : null;
                if (tt == typeof(long)) return vs => vs == null ? 0 : long.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(long?)) return vs => vs == null ? null : long.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (long?)tryval : null;
                if (tt == typeof(sbyte)) return vs => vs == null ? 0 : sbyte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(sbyte?)) return vs => vs == null ? null : sbyte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (sbyte?)tryval : null;
                if (tt == typeof(short)) return vs => vs == null ? 0 : short.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(short?)) return vs => vs == null ? null : short.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (short?)tryval : null;
                if (tt == typeof(uint)) return vs => vs == null ? 0 : uint.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(uint?)) return vs => vs == null ? null : uint.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (uint?)tryval : null;
                if (tt == typeof(ulong)) return vs => vs == null ? 0 : ulong.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(ulong?)) return vs => vs == null ? null : ulong.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (ulong?)tryval : null;
                if (tt == typeof(ushort)) return vs => vs == null ? 0 : ushort.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(ushort?)) return vs => vs == null ? null : ushort.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (ushort?)tryval : null;
                if (tt == typeof(DateTime)) return vs => vs == null ? DateTime.MinValue : DateTime.TryParse(vs, out var tryval) ? tryval : DateTime.MinValue;
                if (tt == typeof(DateTime?)) return vs => vs == null ? null : DateTime.TryParse(vs, out var tryval) ? (DateTime?)tryval : null;
                if (tt == typeof(DateTimeOffset)) return vs => vs == null ? DateTimeOffset.MinValue : DateTimeOffset.TryParse(vs, out var tryval) ? tryval : DateTimeOffset.MinValue;
                if (tt == typeof(DateTimeOffset?)) return vs => vs == null ? null : DateTimeOffset.TryParse(vs, out var tryval) ? (DateTimeOffset?)tryval : null;
                if (tt == typeof(TimeSpan)) return vs => vs == null ? TimeSpan.Zero : TimeSpan.TryParse(vs, out var tryval) ? tryval : TimeSpan.Zero;
                if (tt == typeof(TimeSpan?)) return vs => vs == null ? null : TimeSpan.TryParse(vs, out var tryval) ? (TimeSpan?)tryval : null;
                if (tt == typeof(Guid)) return vs => vs == null ? Guid.Empty : Guid.TryParse(vs, out var tryval) ? tryval : Guid.Empty;
                if (tt == typeof(Guid?)) return vs => vs == null ? null : Guid.TryParse(vs, out var tryval) ? (Guid?)tryval : null;
                if (tt == typeof(BigInteger)) return vs => vs == null ? 0 : BigInteger.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
                if (tt == typeof(BigInteger?)) return vs => vs == null ? null : BigInteger.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (BigInteger?)tryval : null;
                if (tt.NullableTypeOrThis().IsEnum)
                {
                    var tttype = tt.NullableTypeOrThis();
                    var ttdefval = tt.CreateInstanceGetDefaultValue();
                    return vs =>
                    {
                        if (string.IsNullOrWhiteSpace(vs)) return ttdefval;
                        return Enum.Parse(tttype, vs, true);
                    };
                }
                var localTargetType = targetType;
                var localValueType = valueType;
                return vs =>
                {
                    if (vs == null) return null;
                    throw new NotSupportedException($"convert failed {localValueType.DisplayCsharp()} -> {localTargetType.DisplayCsharp()}");
                };
            });
            var valueStr = valueIsNull ? null : valueType == typeof(byte[]) ? encoding.GetString(value as byte[]) : value.ToInvariantCultureToString();
            return func(valueStr);
        }

        internal static string ToInvariantCultureToString(this object obj) => obj is string objstr ? objstr : string.Format(CultureInfo.InvariantCulture, @"{0}", obj);

        private static bool IsNullableType(this Type that) => that.IsArray == false && that?.FullName.StartsWith("System.Nullable`1[") == true;

        private static Type NullableTypeOrThis(this Type that) => that?.IsNullableType() == true ? that.GetGenericArguments().First() : that;

        internal static object CreateInstanceGetDefaultValue(this Type that)
        {
            if (that == null) return null;
            if (that == typeof(string)) return default(string);
            if (that == typeof(Guid)) return default(Guid);
            if (that == typeof(byte[])) return default(byte[]);
            if (that.IsArray) return Array.CreateInstance(that.GetElementType(), 0);
            if (that.IsInterface || that.IsAbstract) return null;
            var ctorParms = that.InternalGetTypeConstructor0OrFirst(false)?.GetParameters();
            if (ctorParms == null || ctorParms.Any() == false) return Activator.CreateInstance(that, true);
            return Activator.CreateInstance(that, ctorParms.Select(a => a.ParameterType.IsInterface ||
                                                                        a.ParameterType.IsAbstract ||
                                                                        a.ParameterType == typeof(string) ||
                                                                        a.ParameterType.IsArray ? null : Activator.CreateInstance(a.ParameterType, null)).ToArray());
        }

        private static ConcurrentDictionary<Type, ConstructorInfo> _dicInternalGetTypeConstructor0OrFirst = new ConcurrentDictionary<Type, ConstructorInfo>();

        private static ConstructorInfo InternalGetTypeConstructor0OrFirst(this Type that, bool isThrow = true)
        {
            var ret = _dicInternalGetTypeConstructor0OrFirst.GetOrAdd(that, tp =>
                tp.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null) ??
                tp.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault());
            if (ret == null && isThrow) throw new ArgumentException($"{that.FullName} has no method to access constructor");
            return ret;
        }

        private static string DisplayCsharp(this Type type, bool isNameSpace = true)
        {
            if (type == null) return null;
            if (type == typeof(void)) return "void";
            if (type.IsGenericParameter) return type.Name;
            if (type.IsArray) return $"{DisplayCsharp(type.GetElementType())}[]";
            var sb = new StringBuilder();
            var nestedType = type;
            while (nestedType.IsNested)
            {
                sb.Insert(0, ".").Insert(0, DisplayCsharp(nestedType.DeclaringType, false));
                nestedType = nestedType.DeclaringType;
            }
            if (isNameSpace && string.IsNullOrWhiteSpace(nestedType.Namespace) == false)
                sb.Insert(0, ".").Insert(0, nestedType.Namespace);

            if (type.IsGenericType == false)
                return sb.Append(type.Name).ToString();

            var genericParameters = type.GetGenericArguments();
            if (type.IsNested && type.DeclaringType.IsGenericType)
            {
                var dic = genericParameters.ToDictionary(a => a.Name);
                foreach (var nestedGenericParameter in type.DeclaringType.GetGenericArguments())
                    if (dic.ContainsKey(nestedGenericParameter.Name))
                        dic.Remove(nestedGenericParameter.Name);
                genericParameters = dic.Values.ToArray();
            }
            if (genericParameters.Any() == false)
                return sb.Append(type.Name).ToString();

            sb.Append(type.Name.Remove(type.Name.IndexOf('`'))).Append("<");
            var genericTypeIndex = 0;
            foreach (var genericType in genericParameters)
            {
                if (genericTypeIndex++ > 0) sb.Append(", ");
                sb.Append(DisplayCsharp(genericType, true));
            }
            return sb.Append(">").ToString();
        }

        /// <summary>
        ///  对象转换为字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ToDic<T>(this T obj) where T : class
        {
            Dictionary<string, string> map = new Dictionary<string, string>();
            var objSte = JsonConvert.SerializeObject(obj);
            map = JsonConvert.DeserializeObject<Dictionary<string, string>>(objSte);
            return map;
        }

        /// <summary>
        ///  字典转为实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T ToClass<T>(this Dictionary<string, string> obj)
        {
            var objSte = JsonConvert.SerializeObject(obj);
            var map = JsonConvert.DeserializeObject<T>(objSte);
            return map;
        }
    }

    public enum GetFormatterEnum
    {
        /// <summary>
        ///  默认类型
        /// </summary>
        Default = 0,

        /// <summary>
        ///  yyyy
        /// </summary>
        yyyy = 4,

        /// <summary>
        ///  yyyy-MM
        /// </summary>
        yyyyMM = 5,

        /// <summary>
        ///  yyyy-MM-dd
        /// </summary>
        yyyyMMdd = 6,

        /// <summary>
        ///  yyyy-MM-dd hh
        /// </summary>
        yyyyMMddhh = 7,

        /// <summary>
        ///  yyyy-MM-dd hh:mm
        /// </summary>
        yyyyMMddhhmm = 8,

        /// <summary>
        ///  yyyy-MM-dd hh:mm:ss
        /// </summary>
        yyyyMMddhhmmss = 9,

        /// <summary>
        ///  yyyy-MM-dd hh:mm:ss:fffffff
        /// </summary>
        yyyyMMddhhmmssfffffff = 10,

        /// <summary>
        /// 用时间组成唯一值
        ///  yyyyMMddhhmmssfffffff
        /// </summary>
        only = 11,
    }
}
