與泛型類反射的遭遇

與泛型類反射的遭遇

    自從採用了類似於 MS PetShop4.0 的經典架構後,無論是技術層面也好,設計思想也罷,都圍繞着這個架構體系在我自己的應用領域中逐步實踐和體會。從貫徹 PetShop WebForm 版本到自己拼裝的混合 WinForm 版本,再到全部基於 WebService 的解決方案。我太沉迷於這個體系架構了,甚至有很多不能理解的地方都是一股腦地全盤模仿,這樣的依賴可不是什麼好事。

在實際應用中, PetShop 自然是不可能滿足於千變萬化的需求。所以做事有自己的思想是很重要的,才華就快橫溢的我自然也非常注重。個人愚見, PetShop 的重要技術主要是分層、反射和緩存,對於每個技術的詳細理解等我以後認爲自己完全參透抑或哪天自信心膨脹到足夠自信了再另起篇幅論之。就目前而言,覺得比較可惜的是 PetShop 沒 有提供關於泛型的使用支持,所以泛型部分的想法都是自己光着膀子摸過來的,因爲看好可謂是設計模式特例的泛型,就算全裸也是要嘗試的。說了半天,纔到正 題。因爲對象操作類的操作方法層面(也叫業務外觀層面)和數據實現層面的依靠接口層面來進行關聯,並以反射技術對數據實現層面的類進行動態加載。在 PetShop 中因爲沒有泛型,所以很好理解,用 Assemly 類的靜態方法 Load 加載指定的程序集後,再用 CreateInstance 方法創建指定名稱的類實例。代碼通常如下:

strPath = KfxyWebSite_SQLServerDAL ;

className = strPath + ".Person.Employee" ;

(IEmployee )Assembly .Load(strPath).CreateInstance(className);

其中 strPath 爲程序集名稱,也就是編譯的項目名稱或 namespace 根名稱; className strPath+ 子命名空間 + 類名稱。

 

但當反射遭遇了 泛型類,整個過程就貌似沒有這麼簡單了。一開始無知的我仍然按普通類的方法去獲取泛型類的實例,結果自然不能成功創建。花了一天時間的資料查詢和反覆實 驗,豁然覺得自己原來對反射所知竟是如此膚淺。可參考的方法查不到幾個,衆多問題似乎都避開了這個話題,偶爾搜索到論壇中和我一樣也有問如何創建泛型類實 例的問題,一看都是無人回答、無人問津。唯一線索只是知道泛型類的反射和普通類的反射是完全不同的概念,其主要區別應該在於 CreateInstance 時的 className 字符串參數的格式。在徹夜未眠的情況下,我仍然不得其解,只是從經驗和信念上覺得可行性是 99% 以上,只是尚未找到方法。幸好在技術羣朋友的提示下,給了我一個較爲複雜的反射創建泛型類實例的示例。大致思路是加載程序集後,遍歷程序集中所有的類,利用 .Net2.0 Type 類新增的對泛型類支持的一些方法來識別出泛型類,並將泛型類的模版類以參數形式添加到該類型中,從而生成一個泛型類。代碼如下:

// 泛型類接口實例。

IDictionary <TeacherTypeInfo , int , string > dal = null ;

// 根據指定的程序集名稱加載程序集。

Assembly asm = Assembly .Load(strPath);

// 獲取程序集中所有的類。

Type [] types = asm.GetTypes();

// 遍歷類集合。

foreach (Type typeX in types)

{

     // 若該類型爲泛型類。

if (typeX.IsGenericType)

{

        // 創建泛型類,其模版類以參數形式添加到該類型。

Type t = typeX.MakeGenericType(typeof (TeacherTypeInfo ), typeof (int ), typeof (string ));

// 使用Activator 類創建該類型的實例。

dal = (IDictionary <TeacherTypeInfo , int , string >)Activator .CreateInstance(t);

}

}

 

以上是我整理精 簡後的代碼,到此思路豁然開朗,兩天以來的痛苦掙扎也終於見到了解脫的曙光,心裏感謝那個技術朋友無數遍。但同時還是存有疑問,覺得似乎不應該像那位朋友 所述對於泛型類只有這樣的方法,畢竟感覺還是稍微複雜了些,從設計角度來說,沒有理由是不能讓第一種方法不成立的。於是調試了 MakeGenericType 後的類,看到了如下的格式:

KfxyWebSite_SQLServerDAL.Profile.Dictionary`3

[

[BlackTeam.ModelEducation.Person.TeacherTypeInfo , BlackTeam.ModelEducation, Version =1.0.0.4, Culture=neutral, PublicKeyToken=null ]

,[System.Int32 , mscorlib, Version =2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]

,[System.String , mscorlib, Version =2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]

]

Site_SQLServerDAL.Profile.Dictionary`3 代表要創建的泛型類全名稱,其中後面的上頓號 3 代表該泛型的模版類個數,該泛型類有三個模版類。後面便在 [ ] 內逐個放置各個模版類型。分析模版類型的格式,主要有類的 FullName Assembly.FullName 兩部分組成。

 

分析到此,不禁立即動手實驗,採用原先的反射方法,一舉成功,不禁長吁口氣,看來自己的先前的判斷未曾有錯,只是差了一口氣,憋了我兩天。現在更爲精簡的代碼如下:

className = strPath + ".Profile.Dictionary`1" ;           

Type t = typeof (TeacherTypeInfo );                     

className += "[[" + t.FullName + "," + t.Assembly.FullName + "]]" ;

IDictionary<TeacherTypeInfo >

dal =(IDictionary<TeacherTypeInfo >)Assembly .Load(strPath).CreateInstance(className);

這裏的泛型類只用了一個模版類,之後就是按照泛型類的格式組織字符串。

 

泛型 + 反射的遭遇由此結束,雖然鬱悶了整整兩天,總算是找到了一個較爲滿意的方法,也受益頗多。將此問題及解決過程記於 Blog ,望能給各位技術同行共同分享。

發佈了86 篇原創文章 · 獲贊 0 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章