久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

優(yōu)化反射性能的總結(jié)(中)

 quasiceo 2013-03-04

問題回顧

上篇博客中,,我介紹了優(yōu)化反射的第一個步驟:用委托調(diào)用代替直接反射調(diào)用,。
然而,,那只是反射優(yōu)化過程的開始,,因為新的問題出現(xiàn)了:如何保存大量的委托,?

如果我們將委托保存在字典集合中,會發(fā)現(xiàn)這種設(shè)計會浪費較多的執(zhí)行時間,,因為這種設(shè)計會引發(fā)三個新問題:
1. 代碼的執(zhí)行路徑變長了,。
2. 字典查找是有成本開銷的。
3. 字典集合的并發(fā)讀寫需要鎖定,,會影響并發(fā)性,。

再來回顧一下上次的測試結(jié)果吧:

雖然通用接口ISetValue將反射性能優(yōu)化了37倍,但是最終的FastSetValue將這個數(shù)字減少到還不到7倍(在CLR4中還不到5倍),。
難道您不覺得遺憾嗎,?

再看看直接調(diào)用與反射調(diào)用的對比,它們的速度相差了上千倍,!

能不能不使用委托,?

既然委托最后引出了三個難以解決的問題,導(dǎo)致優(yōu)化后速度比直接調(diào)用差距太遠,,那我們能不能不使用委托呢,?

委托調(diào)用并不是優(yōu)化反射的唯一方案,我們還有其它方法,,
之所以委托調(diào)用能成為常見的優(yōu)化方案是因為它比較簡單,。

假如我需要用客戶端提交的數(shù)據(jù)來填充某個數(shù)據(jù)對象,考慮到代碼的通用性,,我會用反射寫成這樣:

/// <summary>
/// 從HttpRequest加載obj所需的數(shù)據(jù)
/// </summary>
/// <param name="request"></param>
/// <param name="obj"></param>
public static void LoadDataFromHttpRequest(HttpRequest request, object obj)
{
    PropertyInfo[] properties = obj.GetType().GetProperties();
    foreach( PropertyInfo p in properties ) {
        // 這里只是示意代碼,,假設(shè)數(shù)據(jù)處理不會有異常。
        object val = Convert.ChangeType(request[p.Name], p.PropertyType);
        p.FastSetValue(obj, val);
    }
}

如果我事先知道要加載已知的數(shù)據(jù)類型,,代碼會寫成這樣:

public static void LoadDataFromHttpRequest(HttpRequest request, OrderInfo order)
{
    // 這里只是示意代碼,,假設(shè)數(shù)據(jù)處理不會有異常。
    order.OrderID = int.Parse(request["OrderID"]);
    order.OrderDate = DateTime.Parse(request["OrderDate"]);
    order.SumMoney = decimal.Parse(request["SumMoney"]);
    order.Comment = request["Comment"];
    order.Finished = bool.Parse(request["Finished"]);
}

顯然,,第二段代碼運行效率更快(盡管第一段代碼調(diào)用FastSetValue優(yōu)化了速度),。

大家都知道反射性能較差,直接調(diào)用性能最好,,那么能不能在運行時不使用反射呢,?

的確,使用反射是因為我們事先不知道要處理哪些類型的對象,,因此不得不用反射,, 另外,反射的代碼也更通用,,寫一個方法可以加載所有的數(shù)據(jù)類型,,可認為是一勞永逸的方法,。 不過,就算我們事先不知道要處理哪些對象類型,,但是只要使用反射,,我們完全可以知道任何一個類型包含哪些數(shù)據(jù)成員,, 還能知道這些數(shù)據(jù)成員的數(shù)據(jù)類型,,這一點不用懷疑吧? 既然我們用反射可以知道所有的類型定義信息,,我們是否可以參照代碼生成器的思路去生成代碼呢,? 我們可以參照前面第二段代碼,為【需要處理的類型】生成直接調(diào)用的代碼,,這樣不就徹底解決了反射性能問題了嗎,? 生成代碼的過程,其實也就是個字符串的拼接過程,,難度并不大,,只是比較復(fù)雜而已。

如果前面的答案都是肯定的,,那么現(xiàn)在只有一個問題了:我們能在運行時執(zhí)行拼接生成的字符串代碼嗎,?

答案也是肯定的:能!

CodeDOM:在運行時編譯代碼

回憶一下我們編寫的ASPX頁面,,它們并不是C#代碼,,它們本質(zhì)上就是一個文本文件, 我們可以寫入一些HTML標簽,,還有些標簽上加了 runat="server" 屬性,, 我們還可以在頁面中插入一些C#代碼片段,盡管它們不是我們編譯后的DLL文件,,然而它們就是運行起來了,! 要知道ASP.NET不是ASP,ASP是解釋性的腳本語言,,而ASP.NET是以編譯方式運行的,, 所以,每個ASPX頁面文件最后都是運行編譯后的結(jié)果,。

假設(shè)我有下面一段文本(文本的內(nèi)容是一段C#代碼):

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace OptimizeReflection
{
    public class DemoClass
    {
        public int Id { get; set; }

        public string Name;

        public int Add(int a, int b)
        {
            return a + b;
        }
    }

    public class 用戶手冊
    {
        public static void Main()
        {
            // OptimizeReflection 這個類庫提供了一些擴展方法,,它們用于優(yōu)化常見的反射場景
            // 下面是一些相關(guān)的演示示例。
            
            // 對于屬性的讀寫操作,、方法的調(diào)用操作,,還提供了性能更好的強類型(泛型)版本,可參考Program.cs

            Type instanceType = typeof(DemoClass);
            PropertyInfo propertyInfo = instanceType.GetProperty("Id");
            FieldInfo fieldInfo = instanceType.GetField("Name");
            MethodInfo methodInfo = instanceType.GetMethod("Add");

            // 1. 創(chuàng)建實例對象
            DemoClass obj = (DemoClass)instanceType.FastNew();

            // 2. 寫屬性
            propertyInfo.FastSetValue(obj, 123);
            propertyInfo.FastSetValue2(obj, 123);

            // 3. 讀屬性
            int a = (int)propertyInfo.FastGetValue(obj);
            int b = (int)propertyInfo.FastGetValue2(obj);

            // 4. 寫字段
            fieldInfo.FastSetField(obj, "Fish Li");

            // 5. 讀字段
            string s = (string)fieldInfo.FastGetValue(obj);

            // 6. 調(diào)用方法
            int c = (int)methodInfo.FastInvoke(obj, 1, 2);
            int d = (int)methodInfo.FastInvoke2(obj, 3, 4);

            Console.WriteLine("a={0}; b={1}; c={2}; d={3}; s={4}", a, b, c, d, s);
        }
    }
}

您可以把上面這段文本想像成前面第二個版本的LoadDataFromHttpRequest方法,,如果我們在運行時使用反射也能生成那樣的代碼,, 現(xiàn)在就差把它編譯成程序集了,。下面的代碼演示了如何將一段文本編譯成程序集的過程:

string code = null;

// 1. 生成要編譯的代碼。(示例為了簡單直接從程序集內(nèi)的資源中讀?。?
Stream stram = typeof(CodeDOM).Assembly
            .GetManifestResourceStream("TestOptimizeReflection.用戶手冊.txt");
using( StreamReader sr = new StreamReader(stram) ) {
    code = sr.ReadToEnd();
}

//Console.WriteLine(code);

// 2. 設(shè)置編譯參數(shù),,主要是指定將要引用哪些程序集
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("OptimizeReflection.dll");

// 3. 獲取編譯器并編譯代碼
// 由于我的代碼使用了【自動屬性】特性,所以需要 C# .3.5版本的編譯器,。
// 獲取與CLR匹配版本的C#編譯器可以這樣寫:CodeDomProvider.CreateProvider("CSharp")

Dictionary<string, string> dict = new Dictionary<string, string>();
dict["CompilerVersion"] = "v3.5";
dict["WarnAsError"] = "false";

CSharpCodeProvider csProvider = new CSharpCodeProvider(dict);
CompilerResults cr = csProvider.CompileAssemblyFromSource(cp, code);

// 4. 檢查有沒有編譯錯誤
if( cr.Errors != null && cr.Errors.HasErrors ) {
    foreach( CompilerError error in cr.Errors )
        Console.WriteLine(error.ErrorText);

    return;
}

// 5. 獲取編譯結(jié)果,,它是編譯后的程序集
Assembly asm = cr.CompiledAssembly;

整個過程分為5個步驟,它們已用注釋標識出來了,,這里不再重復(fù)了,。

如何調(diào)用編譯結(jié)果

前面的代碼把一段文本字符串編譯成了程序集,現(xiàn)在還有最后一個問題:如何調(diào)用編譯結(jié)果,?

答案:有二種方法,,
1. 直接調(diào)用方法。
2. 實例化程序集中的類型,,以接口方式調(diào)用方法,。
其實這二種方法都需要使用反射,用反射定位到要調(diào)用的類型和方法,。

第一種方法要求在生成代碼時,,生成的類名和方法名是明確的,在調(diào)用方法時,,我們有二個選擇:
1. 用反射的方式調(diào)用(這里只是一次反射),。
2. 為方法生成委托(用上篇博客介紹的方法),然后基于委托調(diào)用,。

第二種方法要求在生成代碼時,,首先要定義一個接口,保證生成的代碼能實現(xiàn)指定的接口,,
然而用反射找到要調(diào)用的類型名稱,,用反射或者委托調(diào)用構(gòu)造方法創(chuàng)建類型實例,最后基于接口去調(diào)用,。
我們熟悉的ASPX頁面就是采用了這種方式來實現(xiàn)的,。

這二種方法也可以這樣區(qū)分:
1. 如果生成的方法是靜態(tài)方法,應(yīng)該選擇第一種方法,。
2. 如果生成的方法是實例方法,,那么選擇第二種方法是合理的。

對于前面的示例,,我采用了第一種方法了,,因為類名和方法名稱都是事先確定的而且實現(xiàn)起來比較簡單。

// 6. 找到目標方法,并調(diào)用
Type t = asm.GetType("OptimizeReflection.用戶手冊");
MethodInfo method = t.GetMethod("Main");
method.Invoke(null, null);



能不能不使用委托,? 如何用好CodeDOM,?
在這篇博客中我不知道把它們安排在哪里較為合適,算了,,還是把答案留給下篇博客吧,。

招聘信息

公司需要若干名 .net 方面的高級開發(fā)人員,要求熟悉以下技術(shù)領(lǐng)域:
1. .net framework
2. ASP.NET
3. SQL SERVER (T-SQL, SP)
4. JavaScript, jQuery
5. CSS
6. 常見的設(shè)計模式,。

說明:
1. 公司名稱:明源軟件
2. 工作地點:武漢,。
3. 我只是負責【推薦】,具體細節(jié)請發(fā)郵件給我:[email protected]
4. 咨詢招聘相關(guān)的疑問也請發(fā)郵件給我,,評論中的疑問一律不回復(fù),!

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多