dotNet中的反射用法入門教程。本站提示廣大學習愛好者:(dotNet中的反射用法入門教程)文章只能為提供參考,不一定能成為您想要的結果。以下是dotNet中的反射用法入門教程正文
本文實例講述了dotNet中的反射用法。分享給年夜家供年夜家參考,詳細以下:
參考MSDN:
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpcondiscoveringtypeinformationatruntime.htm
提綱:
1、 甚麼是反射
2、 定名空間與拆卸件的關系
3、 運轉期獲得類型信息有甚麼用
4、 若何應用反射獲得類型
5、 若何依據類型來靜態創立對象
6、 若何獲得辦法和靜態挪用辦法
7、 靜態創立拜托
1、甚麼是反射
Reflection,中文翻譯為反射。
這是.Net中獲得運轉時類型信息的方法,.Net的運用法式由幾個部門:‘法式集(Assembly)'、‘模塊(Module)'、‘類型(class)'構成,而反射供給一種編程的方法,讓法式員可以在法式運轉期取得這幾個構成部門的相干信息,例如:
Assembly類可以取得正在運轉的拆卸件信息,也能夠靜態的加載拆卸件,和在拆卸件中查找類型信息,並創立該類型的實例。
Type類可以取得對象的類型信息,此信息包括對象的一切要素:辦法、結構器、屬性等等,經由過程Type類可以獲得這些要素的信息,而且挪用之。
MethodInfo包括辦法的信息,經由過程這個類可以獲得辦法的稱號、參數、前往值等,而且可以挪用之。
諸如斯類,還有FieldInfo、EventInfo等等,這些類都包括在System.Reflection定名空間下。
2、定名空間與拆卸件的關系
許多人對這個概念能夠照樣很不清楚,關於及格的.Net法式員,有需要對這點停止廓清。
定名空間相似與Java的包,但又不完整同等,由於Java的包必需依照目次構造來放置,定名空間則不須要。
拆卸件是.Net運用法式履行的最小單元,編譯出來的.dll、.exe都是拆卸件。
拆卸件和定名空間的關系不是逐個對應,也不相互包括,一個拆卸件外面可以有多個定名空間,一個定名空間也能夠在多個拆卸件中存在,如許說能夠有點隱約,舉個例子:
拆卸件A:
namespace N1 { public class AC1 {…} public class AC2 {…} } namespace N2 { public class AC3 {…} public class AC4{…} }
拆卸件B:
namespace N1 { public class BC1 {…} public class BC2 {…} } namespace N2 { public class BC3 {…} public class BC4{…} }
這兩個拆卸件中都有N1和N2兩個定名空間,並且各聲清楚明了兩個類,如許是完整可以的,然後我們在一個運用法式中援用拆卸件A,那末在這個運用法式中,我們能看到N1上面的類為AC1和AC2,N2上面的類為AC3和AC4。
接著我們去失落對A的援用,加上對B的援用,那末我們在這個運用法式下能看到的N1上面的類釀成了BC1和BC2,N2上面也一樣。
假如我們同時援用這兩個拆卸件,那末N1上面我們就可以看到四個類:AC1、AC2、BC1和BC2。
到這裡,我們可以清晰一個概念了,定名空間只是解釋一個類型是誰人族的,好比有人是漢族、有人是回族;而拆卸件注解一個類型住在哪裡,好比有人住在北京、有人住在上海;那末北京有漢族人,也有回族人,上海有漢族人,也有回族人,這是不抵觸的。
下面我們說了,拆卸件是一個類型棲身的處所,那末在一個法式中要應用一個類,就必需告知編譯器這個類住在哪兒,編譯器能力找到它,也就是說必需援用該拆卸件。
那末假如在編寫法式的時刻,或許不肯定這個類在哪裡,僅僅只是曉得它的稱號,就不克不及應用了嗎?謎底是可以,這就是反射了,就是在法式運轉的時刻供給該類型的地址,而去找到它。
有興致的話,接著往下看吧。
3、運轉期獲得類型信息有甚麼用
有人或許疑問,既然在開辟時就可以夠寫好代碼,干嗎還放到運轉期去做,不但繁瑣,並且效力也受影響。
這就是個見仁見智的成績了,就跟早綁定和晚綁定一樣,運用到分歧的場所。有的人否決晚綁定,來由是消耗效力,然則許多人在享用虛函數帶來的利益的時侯還沒無意識到他曾經用上了晚綁定。這個成績說開去,不是一言半語能講清晰的,所以就點到為止了。
我的意見是,晚綁定可以或許帶來許多設計上的方便,適合的應用可以或許年夜年夜進步法式的復用性和靈巧性,然則任何器械都有兩面性,應用的時侯,須要再三權衡。
接著說,運轉期獲得類型信息究竟有甚麼用呢?
照樣舉個例子來講明,許多軟件開辟者愛好在本身的軟件中留下一些接口,其別人可以編寫一些插件來擴大軟件的功效,好比我有一個媒體播放器,我願望今後可以很便利的擴大辨認的格局,那末我聲明一個接口:
public interface IMediaFormat { string Extension {get;} Decoder GetDecoder(); }
這個接口中包括一個Extension屬性,這個屬性前往支撐的擴大名,另外一個辦法前往一個解碼器的對象(這裡我假定了一個Decoder的類,這個類供給把文件流解碼的功效,擴大插件可以派生之),經由過程解碼器對象我便可以說明文件流。
那末我劃定一切的解碼插件都必需派生一個解碼器,而且完成這個接口,在GetDecoder辦法中前往解碼器對象,而且將其類型的稱號設置裝備擺設到我的設置裝備擺設文件外面。
如許的話,我就不須要在開辟播放器的時侯曉得未來擴大的格局的類型,只須要從設置裝備擺設文件中獲得如今一切解碼器的類型稱號,而靜態的創立媒體魄式的對象,將其轉換為IMediaFormat接口來應用。
這就是一個反射的典范運用。
4、若何應用反射獲得類型
起首我們來看若何取得類型信息。
取得類型信息有兩種辦法,一種是獲得實例對象
這個時侯我僅僅是獲得這個實例對象,獲得的方法或許是一個object的援用,或許是一個接口的援用,然則我其實不曉得它切實其實切類型,我須要懂得,那末便可以經由過程挪用System.Object上聲明的辦法GetType來獲得實例對象的類型對象,好比在某個辦法內,我須要斷定傳遞出去的參數能否完成了某個接口,假如完成了,則挪用該接口的一個辦法:
… public void Process( object processObj ) { Type t = processsObj.GetType(); if( t.GetInterface("ITest") !=null ) … } …
別的一種獲得類型的辦法是經由過程Type.GetType和Assembly.GetType辦法,如:
Type t = Type.GetType("System.String");
須要留意的是,後面我們講到了定名空間和拆卸件的關系,要查找一個類,必需指定它地點的拆卸件,或許在曾經取得的Assembly實例下面挪用GetType。
本拆卸件中類型可以只寫類型稱號,另外一個破例是mscorlib.dll,這個拆卸件中聲明的類型也能夠省略拆卸件稱號(.Net拆卸件編譯的時刻,默許都援用了mscorlib.dll,除非在編譯的時刻明白指定不援用它),好比:
System.String是在mscorlib.dll中聲明的,下面的Type t = Type.GetType("System.String")是准確的
System.Data.DataTable是在System.Data.dll中聲明的,那末:
Type.GetType("System.Data.DataTable")就只能獲得空援用。
必需:
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
5、若何依據類型來靜態創立對象
System.Activator供給了辦法來依據類型靜態創立對象,好比創立一個DataTable:
Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
DataTable table = (DataTable)Activator.CreateInstance(t);
例二:依據有參數的結構器創立對象
namespace TestSpace { public class TestClass { private string _value; public TestClass(string value) { _value=value; } } } … Type t = Type.GetType("TestSpace.TestClass"); Object[] constructParms = new object[] {"hello"}; //結構器參數 TestClass obj = (TestClass)Activator.CreateInstance(t,constructParms); …
把參數依照次序放入一個Object數組中便可
6、若何獲得辦法和靜態挪用辦法
namespace TestSpace { public class TestClass { private string _value; public TestClass() { } public TestClass(string value) { _value = value; } public string GetValue( string prefix ) { if( _value==null ) return "NULL"; else return prefix+" : "+_value; } public string Value { set { _value=value; } get { if( _value==null ) return "NULL"; else return _value; } } } }
下面是一個簡略的類,包括一個有參數的結構器,一個GetValue的辦法,一個Value屬性,我們可以經由過程辦法的稱號來獲得辦法而且挪用之,如:
//獲得類型信息 Type t = Type.GetType("TestSpace.TestClass"); //結構器的參數 object[] constuctParms = new object[]{"timmy"}; //依據類型創立對象 object dObj = Activator.CreateInstance(t,constuctParms); //獲得辦法的信息 MethodInfo method = t.GetMethod("GetValue"); //挪用辦法的一些標記位,這裡的寄義是Public而且是實例辦法,這也是默許的值 BindingFlags flag = BindingFlags.Public | BindingFlags.Instance; //GetValue辦法的參數 object[] parameters = new object[]{"Hello"}; //挪用辦法,用一個object吸收前往值 object returnValue = method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null);
屬性與辦法的挪用年夜同小異,年夜家也能夠參考MSDN
7、靜態創立拜托
拜托是C#中完成事宜的基本,有時刻弗成防止的要靜態的創立拜托,現實上拜托也是一品種型:System.Delegate,一切的拜托都是從這個類派生的
System.Delegate供給了一些靜態辦法來靜態創立一個拜托,好比一個拜托:
namespace TestSpace { delegate string TestDelegate(string value); public class TestClass { public TestClass() { } public void GetValue(string value) { return value; } } }
應用示例:
TestClass obj = new TestClass(); //獲得類型,現實上這裡也能夠直接用typeof來獲得類型 Type t = Type.GetType("TestSpace.TestClass"); //創立署理,傳入類型、創立署理的對象和辦法稱號 TestDelegate method = (TestDelegate)Delegate.CreateDelegate(t,obj,"GetValue"); String returnValue = method("hello");
願望本文所述對年夜家C#法式設計有所贊助。