標籤:sof 關機 object tor dir reac str psi 判斷
反射的概念: 反射提供了封裝程式集、模組和類型的對象(Type類型)。可以使用反射動態建立類型的執行個體,將類型綁定到現有對象,或從現有對象擷取類型並調用其方法或訪問其欄位和屬性。如果代碼中使用了屬性,可以利用反射對它們進行訪問。
一般使用: 工廠類,通過反射建立類的執行個體,實現層與層之間的解耦: 資料層→資料會話層→商務邏輯層。 其中,資料會話層通過反射建立資料層的執行個體,商務邏輯層調用。
反射Type中的函數
//判斷兩個成員是否存在繼承關係 --後者繼承於前者bool b= typeof(Person).IsAssignableFrom(typeof(Student)); //student繼承了person//判斷當前類是否為對象的執行個體Student st = new Student();Person p = new Person();bool s = typeof(Person).IsInstanceOfType(st); //student繼承了person 結果為true bool b = p.GetType().IsInstanceOfType(st); //結果為true GetType當前對象的執行個體//判斷一個類是否為另外一個類的子類 --子類放先 bool c= typeof(Person).IsSubclassOf(typeof(Student)); //判斷一個類是否為抽象類別typeof(Class).IsAbstract
反射中常用類的使用
需求:通過反射獲得Common程式集中的成員,並使用成員
1、把Common.dll放到該應用程式的bin/Debug目錄下
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Common.dll");Assembly ass = Assembly.LoadFile(path); //需要絕對路徑 LoadFile載入路徑程式集內容 -->也不一定要在debug目錄下,自己構建絕對路徑也可Type[] tp = ass.GetTypes(); //獲得程式集中的所有類型 GetExportedTypes();擷取公用類型
2、可以遍曆程式集中的類型,擷取類型的命名空間和類型名稱
foreach (Type item in tp){ Console.WriteLine(item.Name); //類型名稱 --也就是common下類或者介面的名稱 Console.WriteLine(item.Namespace); //命名空間
}
3、建立type對象
a:建立沒有建構函式的對象
object o= ass.CreateInstance("Common.FileCommon"); //FileCommom為Common命名空間的一個類 → 命名空間.類名
b:反射出來的類型有建構函式
Type type = ass.GetType("Common.FileCommon"); //獲得指定名稱的Type對象 object o = Activator.CreateInstance(type, "參數");
註: 當反射出來的類型如果有建構函式,用上面代碼中 ass.CreateInstance則會出現錯誤,如果有建構函式,那麼該如何知道建構函式的參數?
ConstructorInfo [] info= type.GetConstructors(); //查詢所有的建構函式,可以看到建構函式需要傳遞參數的參數類型
4、獲得資料類型中所有的屬性
PropertyInfo [] pinfo = type.GetProperties(); //擷取屬性 然後可以遍曆
5、獲得資料類型中所有的函數
MethodInfo [] minfo =type.GetMethods(); //擷取所有的函數
6、目的:調用函數
MethodInfo method= type.GetMethod("WriteData"); //該類中的writeData方法 method.Invoke(o, "writeData方法的參數"); //o為上文建立的type對象
綜合: 當獲得一個 .dll程式集的時候,需要先擷取所有的類型,也就是這個程式集中的類,然後根據所需要類的名稱,去建立指定名稱的對象 如:Type type = ass.GetType("Common.FileCommon"); ,然後利用type擷取建構函式,所有函數,屬性(還有一些可以 type.方法名 擷取相應的需求)。再選擇建立type對象的方法(構造或無構造)。然後根據獲得的函數來調用,傳入相應的參數。
執行個體1:工廠類通過反射建立類的執行個體:
步驟①:在Web.Config (網頁的為web.config,程式中為app.config) ,設定檔配置:
<appSettings><add key="AssemblyPath" value="Xsh.OA.DAL" /> //路徑<add key="NameSpace" value="Xsh.OA.DAL" /> //命名空間</appSettings>
步驟②:擷取剛才配置的資訊
public static readonly string AssemblyPath = ConfigurationManager.AppSettings["AssemblyPath"];public static readonly string NameSpace = ConfigurationManager.AppSettings["NameSpace"];
步驟③:建立類的執行個體:
public static IUserInfoDal CreateUserInfoDal() { string fullClassName = NameSpace + ".UserInfoDal"; return CreateInstance(fullClassName) as IUserInfoDal; //IUserInfoDal為UserInfoDal繼承的介面。 } private static object CreateInstance(string className) { var assembly= Assembly.Load(AssemblyPath); return assembly.CreateInstance(className); }//此時,在外界調用CreateUserInfoDal這個方法,就會建立了UserInfoDal的執行個體,然後根據該執行個體 點出方法
執行個體2:使用反射製作關機外掛程式
特點:如果需要其他外掛程式,添加路徑下的 .dll檔案即可,刪除外掛程式則刪除相應的.dll檔案
//獲得檔案路徑 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"plug"); //bin/debug/plug存放.dll檔案 string[] files = Directory.GetFiles(path); foreach (string item in files) { Assembly ass = Assembly.LoadFile(item); Type [] types= ass.GetExportedTypes(); for (int i = 0; i < types.Length; i++) { //判斷是否為介面中的類,並不是抽象類別 if (typeof(IPlugin).IsAssignableFrom(types[i]) && !types[i].IsAbstract) { //建立對象 object o = Activator.CreateInstance(types[i]); //獲得指定對象 PropertyInfo psi= types[i].GetProperty("Name"); object o2= psi.GetValue(o); //添加到功能表列(這是winform下的一個功能表列控制項) ToolStripItem tsi= PluginToolStripMenuItem.DropDownItems.Add(o2.ToString()); //註冊單擊事件 tsi.Tag = types[i]; //把資料Object Storage Service到要使用的對象 // tsi.Click += Tsi_Click; tsi.Click += (s, e2) => { Type t = tsi.Tag as Type; MethodInfo mi = t.GetMethod("DoIt"); mi.Invoke(o, new object[] { }); }; } }
總結: 很多.dll檔案可以通過反射的方式來擷取相應的類,類的方法屬性的使用,一些應用程式也可以通過反編譯軟體來擷取一些方法屬性等。(後面如果使用到另外用途,再加補充)
C#反射