C#反射学习总结
詳解C#中的反射
反射(Reflection)
兩個現(xiàn)實中的例子:
1、B超:大家體檢的時候大概都做過B超吧,B超可以透過肚皮探測到你內(nèi)臟的生理情況。這是如何做到
的呢?B超是B型超聲波,它可以透過肚皮通過向你體內(nèi)發(fā)射B型超聲波,當(dāng)超聲波遇到內(nèi)臟壁的時候就會
產(chǎn)生一定的“回音”反射,然后把“回音”進(jìn)行處理就可以顯示出內(nèi)臟的情況了(我不是醫(yī)生也不是聲
學(xué)專家,不知說得是否準(zhǔn)確^_^)。
2、地球內(nèi)部結(jié)構(gòu):地球的內(nèi)部結(jié)構(gòu)大體可以分為三層:地殼、地幔和地核。地殼是固體,地核是液體,
地幔則是半液半固的結(jié)構(gòu)(中學(xué)地理的內(nèi)容,大家還記得吧?)。如何在地球表面不用深入地球內(nèi)部就
知道其內(nèi)部的構(gòu)造呢?對,向地球發(fā)射“地震波”,“地震波”分兩種一種是“橫波”,另一種是“縱
波”。“橫波”只能穿透固體,而“縱波”既可穿透固體又可以穿透液體。通過在地面對縱波和橫波的
反回情況,我們就可以大體斷定地球內(nèi)部的構(gòu)造了。
大家注意到這兩個例子的共同特點,就是從一個對象的外部去了解對象內(nèi)部的構(gòu)造,而且都是利用了波
的反射功能。在.NET中的反射也可以實現(xiàn)從對象的外部來了解對象(或程序集)內(nèi)部結(jié)構(gòu)的功能,哪怕
你不知道這個對象(或程序集)是個什么東西,另外.NET中的反射還可以運態(tài)創(chuàng)建出對象并執(zhí)行它其中
的方法。
反射是.NET中的重要機制,通過反射,可以在運行時獲得程序或程序集中每一個類型(包括類、結(jié)構(gòu)、
委托、接口和枚舉等)的成員和成員的信息。有了反射,即可對每一個類型了如指掌。另外我還可以直
接創(chuàng)建對象,即使這個對象的類型在編譯時還不知道。?
? ??
反射的用途:
? ? (1)使用Assembly定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類型
并創(chuàng)建該類型的實例。?
? ? (2)使用Module了解包含模塊的程序集以及模塊中的類等,還可以獲取在模塊上定義的所有全局方
法或其他特定的非全局方法。?
? ? (3)使用ConstructorInfo了解構(gòu)造函數(shù)的名稱、參數(shù)、訪問修飾符(如pulic 或private)和實現(xiàn)
詳細(xì)信息(如abstract或virtual)等。?
? ? (4)使用MethodInfo了解方法的名稱、返回類型、參數(shù)、訪問修飾符(如pulic 或private)和實
現(xiàn)詳細(xì)信息(如abstract或virtual)等。
? ? (5)使用FiedInfo了解字段的名稱、訪問修飾符(如public或private)和實現(xiàn)詳細(xì)信息(如
static)等,并獲取或設(shè)置字段值。
? ? (6)使用EventInfo了解事件的名稱、事件處理程序數(shù)據(jù)類型、自定義屬性、聲明類型和反射類型
等,添加或移除事件處理程序。?
? ? (7)使用PropertyInfo了解屬性的名稱、數(shù)據(jù)類型、聲明類型、反射類型和只讀或可寫狀態(tài)等,獲
取或設(shè)置屬性值。?
? ? (8)使用ParameterInfo了解參數(shù)的名稱、數(shù)據(jù)類型、是輸入?yún)?shù)還是輸出參數(shù),以及參數(shù)在方法
簽名中的位置等。
反射用到的命名空間:
? ? System.Reflection
? ? System.Type
? ? System.Reflection.Assembly
? ??
反射用到的主要類:
? ? System.Type 類--通過這個類可以訪問任何給定數(shù)據(jù)類型的信息。
? ? System.Reflection.Assembly類--它可以用于訪問給定程序集的信息,或者把這個程序集加載到
程序中。
? ??
System.Type類:
? ? System.Type 類對于反射起著核心的作用。但它是一個抽象的基類,Type有與每種數(shù)據(jù)類型對應(yīng)的
派生類,我們使用這個派生類的對象的方法、字段、屬性來查找有關(guān)該類型的所有信息。
? ? 獲取給定類型的Type引用有3種常用方式:
? ? 使用 C# typeof 運算符。
? ? ? ? Type t = typeof(string);
? ? 使用對象GetType()方法。
? ? ? ? string s = "grayworm";
? ? ? ? Type t = s.GetType();?
? ? 還可以調(diào)用Type類的靜態(tài)方法GetType()。
? ? ? ? Type t = Type.GetType("System.String");
? ? ? ?
? ? 上面這三類代碼都是獲取string類型的Type,在取出string類型的Type引用t后,我們就可以通過t
來探測string類型的結(jié)構(gòu)了。?
? ? ? ? ? ? string n = "grayworm";
? ? ? ? ? ? Type t = n.GetType();
? ? ? ? ? ? foreach (MemberInfo mi in t.GetMembers())
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name);
? ? ? ? ? ? }
? ??
? ? Type類的屬性:
? ? ? ? Name 數(shù)據(jù)類型名
? ? ? ? FullName 數(shù)據(jù)類型的完全限定名(包括命名空間名)
? ? ? ? Namespace 定義數(shù)據(jù)類型的命名空間名
? ? ? ? IsAbstract 指示該類型是否是抽象類型
? ? ? ? IsArray ? 指示該類型是否是數(shù)組
? ? ? ? IsClass ? 指示該類型是否是類
? ? ? ? IsEnum ? 指示該類型是否是枚舉
? ? ? ? IsInterface ? ?指示該類型是否是接口
? ? ? ? IsPublic 指示該類型是否是公有的
? ? ? ? IsSealed 指示該類型是否是密封類
? ? ? ? IsValueType 指示該類型是否是值類型
? ? Type類的方法:
? ? ? ? GetConstructor(), GetConstructors():返回ConstructorInfo類型,用于取得該類的構(gòu)造函
數(shù)的信息
? ? ? ? GetEvent(), GetEvents():返回EventInfo類型,用于取得該類的事件的信息
? ? ? ? GetField(), GetFields():返回FieldInfo類型,用于取得該類的字段(成員變量)的信息
? ? ? ? GetInterface(), GetInterfaces():返回InterfaceInfo類型,用于取得該類實現(xiàn)的接口的信
息
? ? ? ? GetMember(), GetMembers():返回MemberInfo類型,用于取得該類的所有成員的信息
? ? ? ? GetMethod(), GetMethods():返回MethodInfo類型,用于取得該類的方法的信息
? ? ? ? GetProperty(), GetProperties():返回PropertyInfo類型,用于取得該類的屬性的信息
? ? 可以調(diào)用這些成員,其方式是調(diào)用Type的InvokeMember()方法,或者調(diào)用MethodInfo,?
PropertyInfo和其他類的Invoke()方法。?
? ??
? ? 查看類中的構(gòu)造方法:
NewClassw nc = new NewClassw();Type t = nc.GetType();ConstructorInfo[] ci = t.GetConstructors(); //獲取類的所有構(gòu)造函數(shù)foreach (ConstructorInfo c in ci) //遍歷每一個構(gòu)造函數(shù){ParameterInfo[] ps = c.GetParameters(); //取出每個構(gòu)造函數(shù)的所有參數(shù)foreach (ParameterInfo pi in ps) //遍歷并打印所該構(gòu)造函數(shù)的所有參數(shù){Console.Write(pi.ParameterType.ToString()+" "+pi.Name+",");}Console.WriteLine();}
?
? ? 用構(gòu)造函數(shù)動態(tài)生成對象:
? ? ? ? Type t = typeof(NewClassw);
? ? ? ? Type[] pt = new Type[2];
? ? ? ? pt[0] = typeof(string);
? ? ? ? pt[1] = typeof(string);
? ? ? ? //根據(jù)參數(shù)類型獲取構(gòu)造函數(shù)?
? ? ? ? ConstructorInfo ci = t.GetConstructor(pt);?
? ? ? ? //構(gòu)造Object數(shù)組,作為構(gòu)造函數(shù)的輸入?yún)?shù)?
? ? ? ? object[] obj = new object[2]{"grayworm","hi.baidu.com/grayworm"}; ??
? ? ? ? //調(diào)用構(gòu)造函數(shù)生成對象?
? ? ? ? object o = ci.Invoke(obj); ? ?
? ? ? ? //調(diào)用生成的對象的方法測試是否對象生成成功?
? ? ? ? //((NewClassw)o).show(); ? ?
? ??
? ? 用Activator生成對象:
? ? ? ? Type t = typeof(NewClassw);
? ? ? ? //構(gòu)造函數(shù)的參數(shù)?
? ? ? ? object[] obj = new object[2] { "grayworm", "hi.baidu.com/grayworm" }; ??
? ? ? ? //用Activator的CreateInstance靜態(tài)方法,生成新對象?
? ? ? ? object o = Activator.CreateInstance(t,"grayworm","hi.baidu.com/grayworm");?
? ? ? ? //((NewClassw)o).show();
? ? 查看類中的屬性:
NewClassw nc = new NewClassw();Type t = nc.GetType();PropertyInfo[] pis = t.GetProperties();foreach(PropertyInfo pi in pis){Console.WriteLine(pi.Name);}
??
? ? 查看類中的public方法:
NewClassw nc = new NewClassw();Type t = nc.GetType();MethodInfo[] mis = t.GetMethods();foreach (MethodInfo mi in mis){Console.WriteLine(mi.ReturnType+" "+mi.Name);}
? ??
? ? 查看類中的public字段
NewClassw nc = new NewClassw();Type t = nc.GetType();FieldInfo[] fis = t.GetFields();foreach (FieldInfo fi in fis){Console.WriteLine(fi.Name);}
(http://hi.baidu.com/grayworm)
? ? ? ?? ? 用反射生成對象,并調(diào)用屬性、方法和字段進(jìn)行操作?
NewClassw nc = new NewClassw();Type t = nc.GetType();object obj = Activator.CreateInstance(t);//取得ID字段 FieldInfo fi = t.GetField("ID");//給ID字段賦值 fi.SetValue(obj, "k001");//取得MyName屬性 PropertyInfo pi1 = t.GetProperty("MyName");//給MyName屬性賦值 pi1.SetValue(obj, "grayworm", null);PropertyInfo pi2 = t.GetProperty("MyInfo");pi2.SetValue(obj, "hi.baidu.com/grayworm", null);//取得show方法 MethodInfo mi = t.GetMethod("show");//調(diào)用show方法 mi.Invoke(obj, null);
? ? ? ?
System.Reflection.Assembly類?
? ? ?Assembly類可以獲得程序集的信息,也可以動態(tài)的加載程序集,以及在程序集中查找類型信息,并
創(chuàng)建該類型的實例。
? ? 使用Assembly類可以降低程序集之間的耦合,有利于軟件結(jié)構(gòu)的合理化。
? ??
? ? 通過程序集名稱返回Assembly對象
? ? ? ? Assembly ass = Assembly.Load("ClassLibrary831");
? ? 通過DLL文件名稱返回Assembly對象
? ? ? ? Assembly ass = Assembly.LoadFrom("ClassLibrary831.dll");
? ? 通過Assembly獲取程序集中類?
? ? ? ? Type t = ass.GetType("ClassLibrary831.NewClass"); ? //參數(shù)必須是類的全名
? ? 通過Assembly獲取程序集中所有的類
? ? ? ? Type[] t = ass.GetTypes();
? ? ? ?
? ? //通過程序集的名稱反射
? ? Assembly ass = Assembly.Load("ClassLibrary831");
? ? Type t = ass.GetType("ClassLibrary831.NewClass");
? ? object o = Activator.CreateInstance(t, "grayworm", "http://hi.baidu.com/grayworm");
? ? MethodInfo mi = t.GetMethod("show");
? ? mi.Invoke(o, null);
? ?//通過DLL文件全名反射其中的所有類型
? ? Assembly assembly = Assembly.LoadFrom("xxx.dll的路徑");
? ? Type[] aa = a.GetTypes();
? ? foreach(Type t in aa)
? ? {
? ? ? ? if(t.FullName == "a.b.c")
? ? ? ? {
? ? ? ? ? ? object o = Activator.CreateInstance(t);
? ? ? ? }
? ? }
========?
C#反射概念以及實例詳解
?C#反射的入門學(xué)習(xí)首先要明白C#反射提供了封裝程序集、模塊和類型的對象等等。那么這樣可以使用反
射動態(tài)創(chuàng)建類型的實例,將類型綁定到現(xiàn)有對象,或從現(xiàn)有對象獲取類型并調(diào)用其方法或訪問其字段和
屬性。如果代碼中使用了屬性,可以利用反射對它們進(jìn)行訪問。
一個最簡單的C#反射實例,首先編寫類庫如下:?
using System; namespace ReflectionTest { public class WriteTest { //public method with parametors public void WriteString(string s, int i) { Console.WriteLine("WriteString:" + s + i.ToString()); } //static method with only one parametor public static void StaticWriteString(string s) { Console.WriteLine("StaticWriteString:" + s); } //static method with no parametor public static void NoneParaWriteString() { Console.WriteLine("NoParaWriteString"); } } }
使用命令行編譯csc /t:library ReflectTest.cs命令進(jìn)行編譯,生成ReflectTest.dll庫文件。
然后進(jìn)行下列程序的編寫
C#反射學(xué)習(xí)時幾點注意內(nèi)容:
1.指定類庫文件必須使用絕對路徑,不能使用相對路徑(其實感覺有點不合理,不太方便)
2.19行,命名空間和類的名字必須一起指定
3.在例子1種必須實例化反射要反射的類,因為要使用的方法并不是靜態(tài)方法。
4.由于這個方法有兩個參數(shù),可以用這種Object的方法指定參數(shù)也可以直接寫method.Invoke(obj, new?
Object[] { "test", 1 });
5.在例子2種我們想用的方法是一個靜態(tài)方法,這時候Invoke的時候,對于第一個參數(shù)是無視的,也就
是我們寫什么都不會被調(diào)用,即使我們隨便new了一個any這樣的Object,當(dāng)然這種寫法是不推薦的。但
是對應(yīng)在例子1種我們?nèi)绻鸌nvoke的時候用了類型不一致的實例來做為參數(shù)的話,將會導(dǎo)致一個運行時的
錯誤。
6.第三個例子是一個調(diào)用無參數(shù)靜態(tài)方法的例子,這時候兩個參數(shù)我們都不需要指定,用null就可以了
。
再說一個問題,如果調(diào)用的類是靜態(tài)類的時候,需要注意一個問題,肯定我們會想到一個問題,靜態(tài)類
是不能實例化的,這時候,31行的類的實例化的方法我們就不需要了,直接使用Invoke就可以實現(xiàn),否
則將會出現(xiàn)運行時的錯誤,同樣的道理,第一個參數(shù)將會被無視,只要我們傳對了參數(shù)就可以了。
C#反射以及C#反射實例的相關(guān)內(nèi)容就向你介紹到這里,希望對你了解和學(xué)習(xí)C#反射以及C#反射實例應(yīng)用
有所幫助。
========
C# 反射(Reflection)
反射指程序可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。程序集包含模塊,而模塊包含類型,類型又包含成員。反射則提供了封裝程序集、模塊和類型的對象。
您可以使用反射動態(tài)地創(chuàng)建類型的實例,將類型綁定到現(xiàn)有對象,或從現(xiàn)有對象中獲取類型。然后,可
以調(diào)用類型的方法或訪問其字段和屬性。
優(yōu)缺點
優(yōu)點:
1、反射提高了程序的靈活性和擴展性。
2、降低耦合性,提高自適應(yīng)能力。
3、它允許程序創(chuàng)建和控制任何類的對象,無需提前硬編碼目標(biāo)類。
缺點:
1、性能問題:使用反射基本上是一種解釋操作,用于字段和方法接入時要遠(yuǎn)慢于直接代碼。因此反射機
制主要應(yīng)用在對靈活性和拓展性要求很高的系統(tǒng)框架上,普通程序不建議使用。
2、使用反射會模糊程序內(nèi)部邏輯;程序員希望在源代碼中看到程序的邏輯,反射卻繞過了源代碼的技術(shù)
,因而會帶來維護(hù)的問題,反射代碼比相應(yīng)的直接代碼更復(fù)雜。
反射(Reflection)的用途
反射(Reflection)有下列用途:
它允許在運行時查看屬性(attribute)信息。
它允許審查集合中的各種類型,以及實例化這些類型。
它允許延遲綁定的方法和屬性(property)。
它允許在運行時創(chuàng)建新類型,然后使用這些類型執(zhí)行一些任務(wù)。
查看元數(shù)據(jù)
我們已經(jīng)在上面的章節(jié)中提到過,使用反射(Reflection)可以查看屬性(attribute)信息。
System.Reflection 類的 MemberInfo 對象需要被初始化,用于發(fā)現(xiàn)與類相關(guān)的屬性(attribute)。為
了做到這點,您可以定義目標(biāo)類的一個對象,如下:
System.Reflection.MemberInfo info = typeof(MyClass);
下面的程序演示了這點:
using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
? ?public readonly string Url;
? ?public string Topic ?// Topic 是一個命名(named)參數(shù)
? ?{
? ? ? get
? ? ? {
? ? ? ? ?return topic;
? ? ? }
? ? ? set
? ? ? {
? ? ? ? ?topic = value;
? ? ? }
? ?}
? ?public HelpAttribute(string url) ?// url 是一個定位(positional)參數(shù)
? ?{
? ? ? this.Url = url;
? ?}
? ?private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}
namespace AttributeAppl
{
? ?class Program
? ?{
? ? ? static void Main(string[] args)
? ? ? {
? ? ? ? ?System.Reflection.MemberInfo info = typeof(MyClass);
? ? ? ? ?object[] attributes = info.GetCustomAttributes(true);
? ? ? ? ?for (int i = 0; i < attributes.Length; i++)
? ? ? ? ?{
? ? ? ? ? ? System.Console.WriteLine(attributes[i]);
? ? ? ? ?}
? ? ? ? ?Console.ReadKey();
? ? ? }
? ?}
}
當(dāng)上面的代碼被編譯和執(zhí)行時,它會顯示附加到類 MyClass 上的自定義屬性:
HelpAttribute
實例
在本實例中,我們將使用在上一章中創(chuàng)建的 DeBugInfo 屬性,并使用反射(Reflection)來讀取?
Rectangle 類中的元數(shù)據(jù)。
using System;
using System.Reflection;
namespace BugFixApplication
{
? ?// 一個自定義屬性 BugFix 被賦給類及其成員
? ?[AttributeUsage(AttributeTargets.Class |
? ?AttributeTargets.Constructor |
? ?AttributeTargets.Field |
? ?AttributeTargets.Method |
? ?AttributeTargets.Property,
? ?AllowMultiple = true)]
? ?public class DeBugInfo : System.Attribute
? ?{
? ? ? private int bugNo;
? ? ? private string developer;
? ? ? private string lastReview;
? ? ? public string message;
? ? ? public DeBugInfo(int bg, string dev, string d)
? ? ? {
? ? ? ? ?this.bugNo = bg;
? ? ? ? ?this.developer = dev;
? ? ? ? ?this.lastReview = d;
? ? ? }
? ? ? public int BugNo
? ? ? {
? ? ? ? ?get
? ? ? ? ?{
? ? ? ? ? ? return bugNo;
? ? ? ? ?}
? ? ? }
? ? ? public string Developer
? ? ? {
? ? ? ? ?get
? ? ? ? ?{
? ? ? ? ? ? return developer;
? ? ? ? ?}
? ? ? }
? ? ? public string LastReview
? ? ? {
? ? ? ? ?get
? ? ? ? ?{
? ? ? ? ? ? return lastReview;
? ? ? ? ?}
? ? ? }
? ? ? public string Message
? ? ? {
? ? ? ? ?get
? ? ? ? ?{
? ? ? ? ? ? return message;
? ? ? ? ?}
? ? ? ? ?set
? ? ? ? ?{
? ? ? ? ? ? message = value;
? ? ? ? ?}
? ? ? }
? ?}
? ?[DeBugInfo(45, "Zara Ali", "12/8/2012",
Message = "Return type mismatch")]
? ?[DeBugInfo(49, "Nuha Ali", "10/10/2012",
Message = "Unused variable")]
? ?class Rectangle
? ?{
? ? ? // 成員變量
? ? ? protected double length;
? ? ? protected double width;
? ? ? public Rectangle(double l, double w)
? ? ? {
? ? ? ? ?length = l;
? ? ? ? ?width = w;
? ? ? }
? ? ? [DeBugInfo(55, "Zara Ali", "19/10/2012",
? Message = "Return type mismatch")]
? ? ? public double GetArea()
? ? ? {
? ? ? ? ?return length * width;
? ? ? }
? ? ? [DeBugInfo(56, "Zara Ali", "19/10/2012")]
? ? ? public void Display()
? ? ? {
? ? ? ? ?Console.WriteLine("Length: {0}", length);
? ? ? ? ?Console.WriteLine("Width: {0}", width);
? ? ? ? ?Console.WriteLine("Area: {0}", GetArea());
? ? ? }
? ?}//end class Rectangle ?
? ?
? ?class ExecuteRectangle
? ?{
? ? ? static void Main(string[] args)
? ? ? {
? ? ? ? ?Rectangle r = new Rectangle(4.5, 7.5);
? ? ? ? ?r.Display();
? ? ? ? ?Type type = typeof(Rectangle);
? ? ? ? ?// 遍歷 Rectangle 類的屬性
? ? ? ? ?foreach (Object attributes in type.GetCustomAttributes(false))
? ? ? ? ?{
? ? ? ? ? ? DeBugInfo dbi = (DeBugInfo)attributes;
? ? ? ? ? ? if (null != dbi)
? ? ? ? ? ? {
? ? ? ? ? ? ? ?Console.WriteLine("Bug no: {0}", dbi.BugNo);
? ? ? ? ? ? ? ?Console.WriteLine("Developer: {0}", dbi.Developer);
? ? ? ? ? ? ? ?Console.WriteLine("Last Reviewed: {0}",
dbi.LastReview);
? ? ? ? ? ? ? ?Console.WriteLine("Remarks: {0}", dbi.Message);
? ? ? ? ? ? }
? ? ? ? ?}
? ? ? ? ?
? ? ? ? ?// 遍歷方法屬性
? ? ? ? ?foreach (MethodInfo m in type.GetMethods())
? ? ? ? ?{
? ? ? ? ? ? foreach (Attribute a in m.GetCustomAttributes(true))
? ? ? ? ? ? {
? ? ? ? ? ? ? ?DeBugInfo dbi = (DeBugInfo)a;
? ? ? ? ? ? ? ?if (null != dbi)
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? Console.WriteLine("Bug no: {0}, for Method: {1}",
dbi.BugNo, m.Name);
? ? ? ? ? ? ? ? ? Console.WriteLine("Developer: {0}", dbi.Developer);
? ? ? ? ? ? ? ? ? Console.WriteLine("Last Reviewed: {0}",
dbi.LastReview);
? ? ? ? ? ? ? ? ? Console.WriteLine("Remarks: {0}", dbi.Message);
? ? ? ? ? ? ? ?}
? ? ? ? ? ? }
? ? ? ? ?}
? ? ? ? ?Console.ReadLine();
? ? ? }
? ?}
}
當(dāng)上面的代碼被編譯和執(zhí)行時,它會產(chǎn)生下列結(jié)果:
Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks:?
========
?.NET簡談反射(動態(tài)調(diào)用)
http://wangqingpei557.blog.51cto.com/1009349/606400我們繼續(xù)C#基礎(chǔ)知識的學(xué)習(xí),這篇文章主要要講的是我們C#程序員邁向高級C#程序員的關(guān)鍵性的一步。
有的朋友會說事實不是這樣的,我不用反射就不能開發(fā)嗎?當(dāng)然可以,但是用與不用肯定是不一樣的,
任何復(fù)雜抽象的分層架構(gòu)或者說是復(fù)雜的設(shè)計模式均是建立在這些基礎(chǔ)之上的,比如我們要進(jìn)行模塊化
、組件化開發(fā),要嚴(yán)格的消除模塊之間的耦合,要進(jìn)行動態(tài)接口調(diào)用。這樣的強大而靈活的系統(tǒng)開發(fā),
必須要用反射才行;任何技術(shù)都有它存在的價值和意義,只要我們把它用在合適的位置就能發(fā)揮出驚人
的力量;能盡可能的減少我們編寫的代碼,更能是我們的代碼便的清晰簡潔;
下面我們就來學(xué)習(xí)C#中的反射的概念以及怎么使用它,用它能為我們提供什么樣的好處,更重要的是能
否將我們的技術(shù)臺階提升一個高度;
1.什么叫反射
要想快速的學(xué)習(xí)一種技術(shù),首先我們要明白這個技術(shù)是干什么的,我們需要有個大局觀,需要有個總體
的認(rèn)識了解,才能發(fā)揮出每個人本能的理解能力,而不是拉著你來理解我的想法,只有這樣我們才能學(xué)
的更快,不知不覺我們就能形成自己一套獨立的思考能力;[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
自然解釋:射是一種自然現(xiàn)象,表現(xiàn)為受刺激物對刺激物的逆反應(yīng);這是反射的字面解釋,我們看一下計
算機編程中的反射;
編程解釋:通過 System.Reflection 命名空間中的類以及 System.Type,您可以獲取有關(guān)已加載的程序
集和在其中定義的類型(如類、接口和值類型)的信息。 您也可以使用反射在運行時創(chuàng)建類型實例,以
及調(diào)用和訪問這些實例。這是來自微軟官方的MSDN定義;
通過這兩者的比較,我想對于我們初學(xué)者來說,反射就是通過某種事物去反射另一種事物;我們小時候
進(jìn)行喜歡用鏡子對著墻上照,會出現(xiàn)一個個小光圈,這就是很典型的反射例子,我們把它理解成計算機
里的反射就是我用某中對象去反射我無法直接獲取到的東西;[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
1:
這幅圖我想還是比較形象的,至少在我們腦子里已經(jīng)有了這么一個概念,反射、反射就是通過某種中間
設(shè)備獲取到另一端的東西。
C#里面反射跟上面的概念是一樣的,原理也是一樣的,下面我們就用代碼示例來進(jìn)行講解,我想通過本
篇文章的學(xué)習(xí),您一定可以很透徹的理解反射的概念。
2.C#反射示例
2:
在我的解決方案里面有兩個項目,Reflection是控制臺應(yīng)用程序,TestDll是我們所要反射的項目,在這
個項目里面我定義了一個Math類,也就是我們要反射的對象;
為了演示方便,我們需要設(shè)置一下TestDll項目的生成輸出路徑,也就是我們主程序的啟動目錄;
3:
這樣設(shè)置之后,我們項目的輸出文件就會在我們應(yīng)用程序的啟動目錄中,反射也就會方便一點,為了讓
初學(xué)者能少走彎路,我就費點事加上了;
按F6編譯一下,會輸出TestDll.dll文件到Reflection的Debug目錄中,我們切換到Reflection中的Main
方法中開始進(jìn)行反射操作;
using System; ?
using System.Collections.Generic; ?
using System.Text; ?
using System.Reflection; ?
using System.Diagnostics; ?
?
namespace Reflection ?
{ ?
? ? class Program ?
? ? { ?
? ? ? ? static void Main(string[] args) ?
? ? ? ? { ?
? ? ? ? ? ? Assembly dll = Assembly.LoadFile(Environment.CurrentDirectory + "\
\TestDll.dll"); ?
? ? ? ? ? ? Type math = dll.GetType("TestDll.Math", true); ?
? ? ? ? ? ? MethodInfo method = math.GetMethod("add"); ?
? ? ? ? ? ? int count = (int)method.Invoke(null, new object[] { 10, 20 }); ?
? ? ? ? ? ? Console.WriteLine("Invoke Method:" + count.ToString()); ?
? ? ? ? ? ? Console.ReadLine(); ?
? ? ? ? } ?
? ? } ?
} ?
我在Math類中定義了一個靜態(tài)方法add,在這里我們就可以通過反射拿到Math對象進(jìn)行動態(tài)調(diào)用了;
Assembly對象就好比我們?nèi)粘I钪械溺R子,我用這個鏡子去照一下外部的DLL文件,那個文件里面的所
有數(shù)據(jù)就可以反射給我了,我在通過托管對象進(jìn)行一系列的獲取調(diào)用了;具體的對象讀者可以上網(wǎng)搜搜
,大牛們講解的比我詳細(xì),我只是做個入門介紹而已
總結(jié):是不是用反射很神奇,我感覺反射真的很強大,這篇文章只是反射的一個簡單的應(yīng)用,后面我會
講解利用反射進(jìn)行高配置的應(yīng)用系統(tǒng)開發(fā);
http://wangqingpei557.blog.51cto.com/1009349/606400
========
c#反射調(diào)用方法示例
獲取方法的相關(guān)信息的兩種形式
反射是一種允許用戶獲得類信息的C#功能,Type對象映射它代表的底層對象;
在.Net 中, 一旦獲得了Type對象,就可以使用GetMethods()方法獲取此類型支持的方法列表;該方法
的兩種形式:
MethodInfo [] GetMethods()
MethodInfo [] GetMethods(BindingFlags bindingflas) ?:它的參數(shù)帶有一些限制 BindingFlags ?是
一個枚舉
枚舉成員 [DeclaredOnly,Instance ,Public] ? 枚舉成員的功能使用 ?在編譯器中使用"."符號后自己
認(rèn)真觀察 【相信你很快能夠理解】
ParameterInfo[] ?GetParameters() 方法返回一個方法的參數(shù)列表
下面用到的類 MyClass ,為了方便閱讀,我把它折疊了!
復(fù)制代碼 代碼如下:
class MyClass
? ? {
? ? ? ? int x;
? ? ? ? int y;
? ? ? ? public MyClass(int i, int j)
? ? ? ? {
? ? ? ? ? ? this.x = i;
? ? ? ? ? ? this.y = j;
? ? ? ? }
? ? ? ? public int Sum()
? ? ? ? {
? ? ? ? ? ? return x + y;
? ? ? ? }
? ? ? ? public bool IsBetween(int i)
? ? ? ? {
? ? ? ? ? ? if (x < i && i < y)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? public void Set(int a, int b)
? ? ? ? {
? ? ? ? ? ? x = a;
? ? ? ? ? ? y = b;
? ? ? ? }
? ? ? ? public void Set(double a, double b)
? ? ? ? {
? ? ? ? ? ? x = (int)a;
? ? ? ? ? ? y = (int)b;
? ? ? ? }
? ? ? ? public void Show()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("x: " + x + " ?y: ?" + y);
? ? ? ? }
? ? }
MyClass
Main:
復(fù)制代碼 代碼如下:
Type t = typeof(MyClass);//獲得一個表示MyClass類的Type對象
? ? ? ? ? ? Console.WriteLine("獲取當(dāng)前成員的名稱" + t.Name);
? ? ? ? ? ? Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
? ? ? ? ? ? Console.WriteLine("支持的方法");
? ? ? ? ? ? #region 第一種形式
? ? ? ? ? ? //MethodInfo[] mi = t.GetMethods();//顯示Class類中被支持的方法
? ? ? ? ? ? // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? //方法GetMethods() 把 MyClass 的基類 object方法都顯示出來了
? ? ? ? ? ? //下面我們說說 ?GetMethods() 的另外一種形式,有限制的顯示
? ? ? ? ? ? #endregion
? ? ? ? ? ? #region 第二種形式
? ? ? ? ? ? MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly |?
BindingFlags.Instance | BindingFlags.Public);
? ? ? ? ? ? #endregion
? ? ? ? ? ? foreach (MethodInfo m in mi)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //返回后打印出MyClass類中成員的類型(方法的返回值類型)極其方法名稱
? ? ? ? ? ? ? ? Console.Write(" ?" + m.ReturnType.Name + " ?" + m.Name + " (");//ReturnType
獲取此方法的返回類型
? ? ? ? ? ? ? ? ParameterInfo[] pi = m.GetParameters();//獲得方法的參數(shù)
? ? ? ? ? ? ? ? for (int i = 0; i < pi.Length; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? Console.Write(pi[i].ParameterType.Name + " ? " + pi
[i].Name);//ParameterType 獲取該參數(shù)的Type(類型)
? ? ? ? ? ? ? ? ? ? if (i+1<pi.Length)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? Console.Write(", ");
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? Console.WriteLine(")");
? ? ? ? ? ? ? ? Console.WriteLine();
? ? ? ? ? ? } ? ? ? ?
? ? ? ? ? ? Console.ReadKey();
? ?
使用反射調(diào)用方法
上面 討論了怎么獲取一個類型所支持的方法,然而為我們獲取對方法的調(diào)用做了充分的準(zhǔn)備!
MethodInfo類中的Invoke() 方法提供了該技能!
它的一種形式: ?object Invoke(object ?obj,object [] paramenters)
obj 是一個對象引用,將調(diào)用它所指向的對象上的方法,對于static方法,obj必須為null。
所有需要傳遞給方法的參數(shù)都必須在parameters數(shù)組中指定。如果方法不需要參數(shù),則paramenters必須
為null
基類MethodBase的 Invoke()方法返回被調(diào)用方法的返回值
請看下面的事例:
?
MyClass類Set()方法有所改變:
復(fù)制代碼 代碼如下:
public void Set(int a, int b)
? ? ? ? {
Console.WriteLine("Set(int,int)");?
x = a;
y = b;
Show();
? ? ? ? }
? ? ? ? public void Set(double a, double b)
? ? ? ? {
Console.WriteLine("Set(double,double)");
x = (int)a;
y = (int)b;
Show();
? ? ? ? }
復(fù)制代碼 代碼如下:
Type t = typeof(MyClass);
MyClass reflectOb = new MyClass(10, 20);
int val;
Console.WriteLine("Invoke methods in " + t.Name);//調(diào)用MyClass類的方法
Console.WriteLine();
MethodInfo[] mi = t.GetMethods();
foreach (MethodInfo m in mi)//調(diào)用每個方法
{
? ? //獲得方法參數(shù)
? ? ParameterInfo[] pi = m.GetParameters();
? ? if (m.Name.Equals("Set",StringComparison.Ordinal)&&pi[0].ParameterType==typeof(int))
? ? {
? ? ? ? // ? ? 指定 System.String.Compare(System.String,System.String) 和?
System.String.Equals(System.Object)
? ? ? ? // ? ? 方法的某些重載要使用的區(qū)域、大小寫和排序規(guī)則。
? ? ? ? //StringComparison.Ordinal ? 使用序號排序規(guī)則比較字符串?
? ? ? ? object[] obj = new object[2];
? ? ? ? obj[0] = 9;
? ? ? ? obj[1] = 18;
? ? ? ? m.Invoke(reflectOb, obj);
? ? }
? ? else if (m.Name.Equals("Set",StringComparison.Ordinal)&&pi[0].ParameterType==typeof
(double))
? ? {
? ? ? ? object[] obj = new object[2];
? ? ? ? obj[0] = 1.12;
? ? ? ? obj[1] = 23.4;
? ? ? ? m.Invoke(reflectOb, obj);
? ? }
? ? else if (m.Name.Equals("Sum",StringComparison.Ordinal))
? ? {
? ? ? ? val = (int)m.Invoke(reflectOb, null);
? ? ? ? Console.WriteLine("Sum is : " + val);
? ? }
? ? else if (m.Name.Equals("IsBetween", StringComparison.Ordinal))
? ? {
? ? ? ? object[] obj = new object[1];
? ? ? ? obj[0] = 14;
? ? ? ? if ((bool)m.Invoke(reflectOb, obj))
? ? ? ? {
Console.WriteLine("14 is between x and y");?
? ? ? ? }
? ? }
? ? else if (m.Name.Equals("Show",StringComparison.Ordinal))
? ? {
? ? ? ? m.Invoke(reflectOb,null);
? ? }
}
========
C# 利用反射根據(jù)類名創(chuàng)建類的實例對象
“反射”其實就是利用程序集的元數(shù)據(jù)信息。 反射可以有很多方法,編寫程序時請先導(dǎo)入?
System.Reflection 命名空間。
1、假設(shè)你要反射一個 DLL 中的類,并且沒有引用它(即未知的類型):?
Assembly assembly = Assembly.LoadFile("程序集路徑,不能是相對路徑"); // 加載程序集(EXE 或?
DLL)?
dynamic obj = assembly.CreateInstance("類的完全限定名(即包括命名空間)"); // 創(chuàng)建類的實例?
2、若要反射當(dāng)前項目中的類(即當(dāng)前項目已經(jīng)引用它了)可以為:
Assembly assembly = Assembly.GetExecutingAssembly(); // 獲取當(dāng)前程序集?
dynamic obj = assembly.CreateInstance("類的完全限定名(即包括命名空間)"); // 創(chuàng)建類的實例
,返回為 object 類型,需要強制類型轉(zhuǎn)換
3、也可以為:
Type type = Type.GetType("類的完全限定名");?
dynamic obj = type.Assembly.CreateInstance(type);?
4、不同程序集的話,則要裝載調(diào)用,代碼如下:
System.Reflection.Assembly.Load("程序集名稱(不含文件后綴名)").CreateInstance("命名空間.類
名", false);
如:
dynamic o = System.Reflection.Assembly.Load("MyDll").CreateInstance("MyNameSpace.A",?
false);
?
注意:由于要用到dynamic ,需要把target 改為4.0 ,如果編譯時出現(xiàn)“找不到編譯動態(tài)表達(dá)式所需的
一個或多個類型。是否缺少引用?”的錯誤,是因為缺少一個引用,在項目里引用Miscorsoft.CSharp類
庫,添加后就能編譯成功。
補充:
1)反射創(chuàng)建某個類的實例時,必須保證使用類的完全限定名(命名空間 + 類名)。Type.GetType 方法
返回 null 則意味搜索元數(shù)據(jù)中的相關(guān)信息失敗(反射失敗),請確保反射時使用類的完全限定名。
2)反射功能十分強大,沒有什么不能實現(xiàn)的。若實現(xiàn)“跨程序集”,請使用第一種方法創(chuàng)建類的實例,
并反射該實例的字段、屬性、方法、事件... 然后動態(tài)調(diào)用之。
? ? /// <summary>
? ? /// 反射幫助類
? ? /// </summary>
? ? public static class ReflectionHelper
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 創(chuàng)建對象實例
? ? ? ? /// </summary>
? ? ? ? /// <typeparam name="T"></typeparam>
? ? ? ? /// <param name="fullName">命名空間.類型名</param>
? ? ? ? /// <param name="assemblyName">程序集</param>
? ? ? ? /// <returns></returns>
? ? ? ? public static T CreateInstance<T>(string fullName, string assemblyName)
? ? ? ? {
? ? ? ? ? ? string path = fullName + "," + assemblyName;//命名空間.類型名,程序集
? ? ? ? ? ? Type o = Type.GetType(path);//加載類型
? ? ? ? ? ? object obj = Activator.CreateInstance(o, true);//根據(jù)類型創(chuàng)建實例
? ? ? ? ? ? return (T)obj;//類型轉(zhuǎn)換并返回
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 創(chuàng)建對象實例
? ? ? ? /// </summary>
? ? ? ? /// <typeparam name="T">要創(chuàng)建對象的類型</typeparam>
? ? ? ? /// <param name="assemblyName">類型所在程序集名稱</param>
? ? ? ? /// <param name="nameSpace">類型所在命名空間</param>
? ? ? ? /// <param name="className">類型名</param>
? ? ? ? /// <returns></returns>
? ? ? ? public static T CreateInstance<T>(string assemblyName, string nameSpace, string?
className)
? ? ? ? {
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? string fullName = nameSpace + "." + className;//命名空間.類型名
? ? ? ? ? ? ? ? //此為第一種寫法
? ? ? ? ? ? ? ? object ect = Assembly.Load(assemblyName).CreateInstance(fullName);//加載程
序集,創(chuàng)建程序集里面的 命名空間.類型名 實例
? ? ? ? ? ? ? ? return (T)ect;//類型轉(zhuǎn)換并返回
? ? ? ? ? ? ? ? //下面是第二種寫法
? ? ? ? ? ? ? ? //string path = fullName + "," + assemblyName;//命名空間.類型名,程序集
? ? ? ? ? ? ? ? //Type o = Type.GetType(path);//加載類型
? ? ? ? ? ? ? ? //object obj = Activator.CreateInstance(o, true);//根據(jù)類型創(chuàng)建實例
? ? ? ? ? ? ? ? //return (T)obj;//類型轉(zhuǎn)換并返回
? ? ? ? ? ? }
? ? ? ? ? ? catch
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //發(fā)生異常,返回類型的默認(rèn)值
? ? ? ? ? ? ? ? return default(T);
? ? ? ? ? ? }
? ? ? ? }
? ? }
========
總結(jié)
- 上一篇: Python文件操作学习总结
- 下一篇: c# char unsigned_dll