久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    玩轉動態編譯:二、實戰

     賈朋亮博客 2014-10-10
    玩轉動態編譯:一、初識中,我們已經學會了最簡單的使用動態編譯。今天直接由實戰入手,看看真實情況下的動態編譯能為我們來帶什么。

    今天要演示的實例是一個在實際開發中經常遇到的情況,對象轉Json。

    我將會使用2種方式分別做一個轉json字符串的實例,1:反射;2:動態編譯

    • 分析問題

    分析C#對象在json中的映射。總體來說json對象只有幾種情況

    1. 鍵值對對象,由多組鍵對象+值對象構成,最外面是一對花括號包裹,鍵值對對象同時也可作為“值對象”使用
    2. 數組對象,由多個值對象構成,最外面是一對中括號包裹,數組對象同時也可作為“值對象”使用
    3. 鍵對象,由一個字符串構成,在鍵值對對象組成中擔任“鍵”
    4. 一般值對象,由一個單獨的值構成,可以是string,int,bool等,在鍵值對對象或者數組對象中擔任“值”
    5. 特殊值對象,鍵值對對象或數組對象,本身也可以作為值對象使用

    這4中對象分別對應了C#中的:

    鍵值對對象 -> 任何有公開屬性的對象,或者實現了IDictionary的對象,或者同時擁有Key和Value枚舉的對象

    數組對象 -> 實現了IEnumerator或者IEnumerable接口的對象

    鍵對象 -> string對象

    一般值對象 -> System命名空間下的簡單值類型,包括int,bool,float,DateTime等,外加一個string

    • 編寫基類

    為了滿足所有類型的轉換需求,首先要建立一個抽象基類JsonConverter

    復制代碼
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace blqw
    {
        /// <summary>
        /// 用于將C#轉換為Json字符串的抽象基類,基類提供基本類型的轉換,也可以重寫
        /// </summary>
        public abstract class JsonConverter
        {
            public abstract string ToJson(object obj);
    
            public const string Flag = "\"";
            //基本類型轉換Json字符串
            //bool值轉為true,false,
            //數值類型直接輸出,日期類型轉為指定格式字符串,前后加上雙引號
            //字符串內部(\)替換為(\\),(")替換(\"),前后加上雙引號
            //Guid轉為沒有-的字符串,前后加上雙引號
            //方法命名按照From + 參數類名,為了一會反射和動態編譯的時候查找方法更方便
            public virtual string FromBoolean(Boolean val) { return val ? "true" : "false"; }
            public virtual string FromByte(Byte val) { return val.ToString(); }
            public virtual string FromChar(Char val) { return val.ToString(); }
            public virtual string FromDateTime(DateTime val) { return Flag + val.ToString("yyyy-MM-dd HH:mm:ss") + Flag; }
            public virtual string FromDecimal(Decimal val) { return val.ToString(); }
            public virtual string FromDouble(Double val) { return val.ToString(); }
            public virtual string FromInt16(Int16 val) { return val.ToString(); }
            public virtual string FromInt32(Int32 val) { return val.ToString(); }
            public virtual string FromInt64(Int64 val) { return val.ToString(); }
            public virtual string FromSByte(SByte val) { return val.ToString(); }
            public virtual string FromSingle(Single val) { return val.ToString(); }
            public virtual string FromString(String val) { return Flag + val.Replace(@"\",@"\\").Replace("\"",@"\""")+ Flag; }
            public virtual string FromUInt16(UInt16 val) { return val.ToString(); }
            public virtual string FromUInt32(UInt32 val) { return val.ToString(); }
            public virtual string FromUInt64(UInt64 val) { return val.ToString(); }
            public virtual string FromGuid(Guid val) { return Flag + val.ToString("N") + Flag; }
            //枚舉
            public virtual string FromEnum(Enum val) { return Flag + val.ToString() + Flag; }
            //轉換數組對象
            public virtual string FromArray(IEnumerator ee)
            {
                List<string> list = new List<string>();
                while (ee.MoveNext())
                {
                    list.Add(ToJson(ee.Current));
                }
                return "[" + string.Join(",", list) + "]";
            }
            //轉換鍵值對對象
            public virtual string FromKeyValue(IEnumerable keys, IEnumerable values)
            {
                List<string> list = new List<string>();
                var ke = keys.GetEnumerator();
                var ve = values.GetEnumerator();
                bool a, b;
                while ((a = ke.MoveNext()) & (b = ve.MoveNext()))
                {
                    if (ke.Current == null || (ke.Current + "").Length == 0)
                    {
                        throw new ArgumentNullException("Json鍵不能為null或空");
                    }
                    list.Add(Flag + ke.Current + Flag + ":" + ToJson(ve.Current));
                }
                if (a != b)
                {
                    throw new ArgumentException("鍵值對的鍵和值個數不一致");
                }
                return "{" + string.Join(",", list) + "}";
            }
        }
    }
    復制代碼

    這個類完成大部分基礎類型的轉換工作,只有一個方法等待實現

    • 反射實現
    復制代碼
    using System;
    using System.Collections;
    
    namespace blqw
    {
        /// <summary> 實現JsonConverter,利用反射構造Json字符串
        /// </summary>
        public class JsonConverter_Reflection : JsonConverter
        {
            //靜態化,方便反復調用
            readonly static Type _ThisType = typeof(JsonConverter_Reflection);
            //這個方法里面的主要工作的就是obj的類型,來調用基類的不同方法,返回json字符串
            public override string ToJson(object obj)
            {
                if (obj == null)
                {
                    return "null";
                }
                var type = obj.GetType();
                type = Nullable.GetUnderlyingType(type) ?? type;//如果是可空值類型則獲取其內部基礎類型
                if (type.Namespace == "System")//判斷如果是在System命名空間下的類型
                {
                    var met = _ThisType.GetMethod("From" + type.Name);//使用 From+類型名稱 作為方法名查找方法
                    if (met != null)//如果存在這樣的方法,直接反射調用方法
                    {
                        return (string)met.Invoke(this, new object[] { obj });
                    }
                }
                if (obj is Enum)//枚舉
                {
                    return FromEnum((Enum)obj);
                }
                if (obj is IDictionary)//對象實現IDictionary
                {
                    var dic = (IDictionary)obj;
                    return FromKeyValue(dic.Keys, dic.Values);
                }
                if (obj is IEnumerator)//對象實現IEnumerator
                {
                    return FromArray((IEnumerator)obj);
                }
                if (obj is IEnumerable)//對象實現IEnumerable
                {
                    return FromArray(((IEnumerable)obj).GetEnumerator());
                }
                //上面都不行,反射對象屬性
                var ps = type.GetProperties();
                if (ps.Length == 0)//如果對象屬性為空,直接返回空json
                {
                    return "{}";
                }
                string[] str = new string[ps.Length];
                int i = 0;
                foreach (var p in ps)//反射對象屬性,和屬性值,構造Json字符串,處理屬性值的時候遞歸調用本身方法進行處理
                {
                    str[i++] = Flag + p.Name + Flag + ":" + ToJson(p.GetValue(obj));
                }
                return "{" + string.Join(",", str) + "}";
    
            }
        }
    }
    復制代碼

    • 動態編譯實現

    動態編譯的邏輯是這樣的:因為在程序運行中,每個類型的相對應屬性不可能發生更變,所以可以針對每個類型生成一個方法,

    比如User對象

    class User
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public bool Sex { get; set; }
    }

    我們可以為User對象生成一個方法,例如這個

    public static string ToJson(User user)
    {
        return "{ \"Name\":\"" + user.Name + "\",\"Age\":" + user.Age + ",\"Sex\",\"" + (user.Sex ? "" : "") + "\"}";
    }

    這個方法如果自己寫實在是太蛋疼了,但是我們可以在程序中構造,由于動態編譯來完成,然后把方法委托緩存起來,下次就可以直接使用了

    整個方法是這樣的

    復制代碼
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace blqw
    {
        /// <summary> 實現JsonConverter,利用動態編譯的方式輸出Json字符串
        /// </summary>
        public class JsonConverter_Dyncmp : JsonConverter
        {
            //靜態化,方便反復調用
            readonly static Type _ThisType = typeof(JsonConverter_Dyncmp);
            public override string ToJson(object obj)
            {//跟剛才那個方法邏輯基本是一致的只有最后實現的部分不一樣
                if (obj == null)
                {
                    return "null";
                }
                var type = obj.GetType();
                type = Nullable.GetUnderlyingType(type) ?? type;//如果是可空值類型則獲取其內部基礎類型
                if (type.Namespace == "System")//判斷如果是在System命名空間下的類型
                {
                    var met = _ThisType.GetMethod("From" + type.Name);//使用 From+類型名稱 作為方法名查找方法
                    if (met != null)//如果存在這樣的方法,直接反射調用方法
                    {
                        return (string)met.Invoke(this, new object[] { obj });
                    }
                }
                if (obj is Enum)//枚舉
                {
                    return FromEnum((Enum)obj);
                }
                if (obj is IDictionary)//對象實現IDictionary
                {
                    var dic = (IDictionary)obj;
                    return FromKeyValue(dic.Keys, dic.Values);
                }
                if (obj is IEnumerator)//對象實現IEnumerator
                {
                    return FromArray((IEnumerator)obj);
                }
                if (obj is IEnumerable)//對象實現IEnumerable
                {
                    return FromArray(((IEnumerable)obj).GetEnumerator());
                }
                //上面都不行,動態編譯方法
                {
                    MethodInfo met;
                    //在緩存中查詢是否已經編譯過了
                    if (MethodCache.TryGetValue(type, out met) == false)
                    {//如果沒有,則編譯,并加入緩存
                        var code = CreateCode(type);//獲得代碼
                        var ass = DynamicCompile_1.CompileAssembly(code, typeof(Json), typeof(StringBuilder), typeof(IDictionary), typeof(Enum), typeof(IEnumerable), typeof(IEnumerator));//編譯
                        met = ass.GetTypes()[0].GetMethods()[0];//反射編譯后的方法
                        MethodCache.Add(type, met);//加入緩存
                    }
                    return (string)met.Invoke(null, new object[] { obj });//執行方法,等到json字符串
                }
    
            }
            //動態編譯方法緩存
            private static Dictionary<Type, MethodInfo> MethodCache = new Dictionary<Type, MethodInfo>();
            //得到一個類型的可視名稱,比如泛型類,List`1這種名字是不可以用的
            private static string TypeDisplayName(Type type)
            {
                if (type == null)
                {
                    return "null";
                }
                if (type.IsGenericType)
                {
                    var arr = type.GetGenericArguments();
                    string gname = type.GetGenericTypeDefinition().FullName;
                    gname = gname.Remove(gname.IndexOf('`'));
                    if (arr.Length == 1)
                    {
                        return gname + "<" + TypeDisplayName(arr[0]) + ">";
                    }
                    StringBuilder sb = new StringBuilder(gname);
                    sb.Append("<");
                    foreach (var a in arr)
                    {
                        sb.Append(TypeDisplayName(a));
                        sb.Append(",");
                    }
                    sb[sb.Length - 1] = '>';
                    return sb.ToString();
                }
                else
                {
                    return type.FullName.Replace('+', '.');
                }
            }
            //根據類型,創建生成Json字符串的動態代碼
            private string CreateCode(Type type)
            {
                //大體的邏輯就是 根據屬性的類型
                var className = "_" + Guid.NewGuid().ToString("N");
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("public class " + className);
                sb.AppendLine("{");
                sb.AppendFormat("public static string a({0} obj)", TypeDisplayName(type));
                sb.AppendLine("{");
                sb.Append("return new StringBuilder()");
                var ee = type.GetProperties().GetEnumerator();
                string[] baseMethods = base.GetType().GetMethods().Select(it => it.Name).ToArray();
                PropertyInfo p;
                string method;
                Type ptype;
                string pre = "{";
                while (ee.MoveNext())
                {
                    p = (PropertyInfo)ee.Current;
                    ptype = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType;
                    sb.Append(".Append('").Append(pre).Append("\\'").Append(p.Name).Append("\\':')");
                    pre = ",";
                    method = "From" + ptype.Name;
                    if (ptype.Namespace == "System" && baseMethods.Contains(method))
                    {
                        sb.Append(".Append(Json.Converter2.").Append(method).Append("((").Append(ptype.FullName).Append(")obj.").Append(p.Name).Append("))");
                    }
                    else if (ptype.IsEnum)//屬性是枚舉
                    {
                        sb.Append(".Append(Json.Converter2.FromEnum((Enum)obj.").Append(p.Name).Append("))");
                    }
                    else if (ptype.GetInterface("IDictionary") == typeof(IDictionary))//屬性實現IDictionary
                    {
                        sb.Append(".Append(Json.Converter2.FromKeyValue(((IDictionary)obj.").Append(p.Name).Append(").Keys,((IDictionary)obj.").Append(p.Name).Append(").Values))");
                    }
                    else if (ptype.GetInterface("IEnumerator") == typeof(IEnumerator))//對象實現IEnumerator
                    {
                        sb.Append(".Append(Json.Converter2.FromArray((IEnumerator)obj.").Append(p.Name).Append("))");
                    }
                    else if (ptype.GetInterface("IEnumerable") == typeof(IEnumerable))//對象實現IEnumerable
                    {
                        sb.Append(".Append(Json.Converter2.FromArray(((IEnumerable)obj.").Append(p.Name).Append(").GetEnumerator()))");
                    }
                    else
                    {
                        sb.Append(".Append(Json.ToJson_2(obj.").Append(p.Name).Append("))");
                    }
                }
                sb.AppendLine(".Append('}').ToString();").AppendLine("}").AppendLine("}");
                return sb.ToString().Replace('\'', '"');
            }
        }
    
    
    }
    復制代碼

    • 測試調用
    復制代碼
    namespace blqw
    {
        public static class Json
        {
            public static JsonConverter Converter1 = new JsonConverter_Reflection();
            public static JsonConverter Converter2 = new JsonConverter_Dyncmp();
            
    
            public static string ToJson_1(object obj)
            {
                return Converter1.ToJson(obj);
            }
    
            public static string ToJson_2(object obj)
            {
                return Converter2.ToJson(obj);
            }
        }
    }
    復制代碼

    ToJson_1就是反射方式
    ToJson_2是動態編譯的方式
    再附上測試代碼
    一個非常復雜的對象
    復制代碼
    using System;
    using System.Collections.Generic;
    
    /// <summary> 用戶對象
    /// </summary>
    public class User
    {
        /// <summary> 唯一ID
        /// </summary>
        public Guid UID { get; set; }
        /// <summary> 用戶名稱
        /// </summary>
        public string Name { get; set; }
        /// <summary> 生日
        /// </summary>
        public DateTime? Birthday { get; set; }
        /// <summary> 性別
        /// </summary>
        public UserSex Sex { get; set; }
        /// <summary> 是否刪除標記
        /// </summary>
        public bool IsDeleted { get; set; }
        /// <summary> 最近登錄記錄
        /// </summary>
        public List<DateTime> LoginHistory { get; set; }
        /// <summary> 聯系信息
        /// </summary>
        public UserInfo Info { get; set; }
    }
    /// <summary> 用戶性別
    /// </summary>
    public enum UserSex
    {
        /// <summary>/// </summary>
        Male,
        /// <summary>/// </summary>
        Female
    }
    /// <summary> 用戶信息
    /// </summary>
    public class UserInfo
    {
        /// <summary> 地址
        /// </summary>
        public string Address { get; set; }
        /// <summary> 聯系方式
        /// </summary>
        public Dictionary<string, string> Phone { get; set; }
        /// <summary> 郵政編碼
        /// </summary>
        public int ZipCode { get; set; }
    }
    復制代碼
    復制代碼
    static User GetUser()
    {//這里我盡量構造一個看上去很復雜的對象,并且這個對象幾乎涵蓋了所有常用的類型
        User user = new User();
        user.UID = Guid.NewGuid();
        user.Birthday = new DateTime(1986, 10, 29, 18, 00, 00);
        user.IsDeleted = false;
        user.Name = "blqw";
        user.Sex = UserSex.Male;
        user.LoginHistory = new List<DateTime>();
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(8, 00, 00)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(10, 10, 10)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(12, 33, 56)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(17, 25, 18)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(23, 06, 59)));
        user.Info = new UserInfo();
        user.Info.Address = "廣東省廣州市";
        user.Info.ZipCode = 510000;
        user.Info.Phone = new Dictionary<string, string>();
        user.Info.Phone.Add("手機", "18688888888");
        user.Info.Phone.Add("電話", "82580000");
        user.Info.Phone.Add("短號", "10086");
        user.Info.Phone.Add("QQ", "21979018");
        return user;
    }
    復制代碼

    測試用代碼:
    復制代碼
    static void Main(string[] args)
    {
        var user = GetUser();
        Stopwatch sw = new Stopwatch();
        sw.Restart();
        for (int i = 0; i < 10000; i++)
        {
            Json.ToJson_1(user);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds + "ms");
        sw.Restart();
        for (int i = 0; i < 10000; i++)
        {
            Json.ToJson_2(user);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds + "ms");
    
        Console.WriteLine();
        Console.WriteLine(Json.ToJson_1(user));
    
        Console.WriteLine();
        Console.WriteLine(Json.ToJson_2(user));
    }
    復制代碼

    • 查看結果

    • 小結
    看到結論,可能有人要開始說了:貌似第二個動態編譯的方法性能還不如反射的好啊~~
    目前的情況來看呢,確實是這樣的.不過動態編譯當然不止如此,
    性能上的問題是一定要解決的

    欲知后事如何,且聽下回分解

     
    我寫的文章,除了純代碼,其他的都是想表達一種思想,一種解決方案.希望各位看官不要局限于文章中的現成的代碼,要多關注整個文章的主題思路,謝謝!
    我發布的代碼,沒有任何版權,遵守WTFPL協議(如有引用,請遵守被引用代碼的協議)
    qq群:5946699 暗號:C#交流 希望各位喜愛C#的朋友可以在這里交流學習,分享編程的心得和快樂

      本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
      轉藏 分享 獻花(0

      0條評論

      發表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 国产农村妇女毛片精品久久| 亚洲AV无码专区电影在线观看| 日韩欧美不卡一卡二卡3卡四卡2021免费 | 国产精品亚洲一区二区三区喷水| 在线精品国产一区二区三区| 亚洲精品动漫免费二区| 国产尤物精品自在拍视频首页| 青青草国产线观看| 色翁荡熄又大又硬又粗又视频| 亚洲人妻中文字幕一区| 狠狠色丁香婷婷综合尤物 | 亚洲AV高清一区二区三区尤物| 亚洲更新最快无码视频| 成人免费AA片在线观看| 奇米影视7777狠狠狠狠色| 在线日韩日本国产亚洲| 乱码精品一区二区三区| 亚洲国产精品成人AV在线| 5D肉蒲团之性战奶水欧美| 日日碰狠狠添天天爽无码| 377P欧洲日本亚洲大胆| 成人免费看片又大又黄| 日本一区二区三区免费播放视频站| 又黄又无遮挡AAAAA毛片| 精品国产精品中文字幕| 免费AV手机在线观看片| 亚洲日本欧洲二区精品| 国内精品久久久久影院优| 狠狠亚洲色一日本高清色| 香蕉影院在线观看| 久久精品免视看国产成人| 亚洲AV永久无码精品三区在线| 艳女性享受在线观看| 真人性囗交视频| 久久久亚洲欧洲日产国码农村| 欧洲亚洲精品免费二区| 国产AV激情久久无码天堂| 国产揄拍国产精品| 欧美激情一区二区三区成人| 久久精品A一国产成人免费网站| 亚洲国产良家在线观看|