System.Type 類別 代表型別宣告:類別型別、介面型別、陣列型別、值型別、列舉型別、型別參數、泛型型別定義,以及開放式或封閉式的建構泛型型別。
…最下面的備註…
Type 是 System.Reflection 功能的根,也是存取中繼資料 (Metadata) 的主要方法。 使用 Type 的成員以取得型別宣告的資訊,例如建構函式 (Constructor)、方法、欄位、屬性和類別的事件,以及模組和部署類別的組件。 C# typeof 運算子 (在 Visual Basic 中為 GetType 運算子,在 Visual C++ 中則為 typeid 運算子) 會傳回 Type 物件。 Type 物件表示型別是唯一的;也就是兩個 Type 物件參考只有在它們表示相同型別時才會參考相同物件。 如此就允許使用參考的相等來比較 Type 物件。…
System.Type 類別簡易介紹
透過 MSDN,我們知道,了解 Reflection 時也必須一併了解 System.Type 類別,不過 System.Type 類別是個大類別,當我看完那長長一列的屬性與方法後,頭也昏的。System.Type 類別的屬性與方法
其實沒那麼複雜,就 Type 屬性或方法而言,基本上分成兩大類,- Getxxx:Get 開頭為一類
- Isxxx:Is 開頭為一類
Isxxx 所代表的是「判斷」,你能拿 Isxxx 來判斷此型別(Type),例如,Type.IsArray() 判斷是否為陣列。
當我們取得型別(Type)後,我們就能夠透過 Getxxx 或 Isxxx 來取得與判斷此型別。所以,回過頭來,我們要來介紹,取得取得型別的4種方法。
取得型別的4種方法
取得型別的4種方法分別是:
- Assembly 取得 Type
- Module 取得 Type
- Object 取得 Type
- VB GetType() 取得 Type
以下一一介紹。
Assembly 取得 Type
ShowTypeFromAssembly() 副程式,由傳入的組件需得型別資料。''' <summary> ''' 由組件來取得型別 ''' </summary> ''' <param name="asm">Assembly (組件)</param> Sub ShowTypeFromAssembly(asm As Assembly) Dim asmTypes() As Type = asm.GetTypes() Console.WriteLine("組件取得:") For Each asmType In asmTypes Console.WriteLine("Type: {0}", asmType.Name) Next Console.WriteLine() End Sub
我們來看主程式:
Dim d As Assembly = Assembly.GetExecutingAssembly() ShowTypeFromAssembly(d)
我們先取得正在執行的組件,指後傳入副程式顯示型別資料。
我們得到的結果:
組件取得: Type: MyApplication Type: MyComputer Type: MyProject Type: MyWebServices Type: ThreadSafeObjectProvider`1 Type: InternalXmlHelper Type: RemoveNamespaceAttributesClosure Type: Module1 Type: Example Type: Resources Type: MySettings Type: MySettingsProperty
如果你想載入一個目錄下所有組件,那你可以參考這一篇「每周源代码19 – LINQ,多些What,少些How」很棒的文章,裡面給了一段關於 Assembly 載入很棒程式碼。
以下是我轉換為Visual Basic後的程式碼(注意,此程式碼無法執行,此為原型程式碼)
myListOfInstances = (From file In Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins"), "*.dll") Let a = Assembly.LoadFrom(file) From t In a.GetTypes() Where Not t.IsAbstract AndAlso t.BaseType = GetType(MyBaseClass) Select CType(MyBaseClass,Activator.CreateInstance(t, credentials))).ToList()
有問題,請參考原文章。
Module 取得 Type
與 Assembly 取得 Type 不同,上面是傳入 Assembly 直接取得 Type,而在 ShowTypeFromModule() 副程式中,我們是傳入 Assembly,先由 Assembly 取得 Module 後,在從 Module 裡取得 Type。''' <summary> ''' 由模組取得型別 ''' </summary> ''' <param name="asm">Assembly (組件)</param> Sub ShowTypeFromModule(asm As Assembly) Dim mods() As [Module] = asm.GetModules() Dim m As [Module] = mods(0) Dim modTypes() As Type = m.GetTypes() Console.WriteLine("模組取得:") For Each modType In modTypes Console.WriteLine("Type: {0}", modType.Name) Next Console.WriteLine() End Sub
主程式和上面一樣,傳入 Assembly 的 d:
ShowTypeFromModule(d)
ShowTypeFromModule() 副程式執行結果:
模組取得: Type: MyApplication Type: MyComputer Type: MyProject Type: MyWebServices Type: ThreadSafeObjectProvider`1 Type: InternalXmlHelper Type: RemoveNamespaceAttributesClosure Type: Module1 Type: Example Type: Resources Type: MySettings Type: MySettingsProperty
從目前結果來看,從 Assembly 取得 Type = 從 Module 取得 Type。
Object 取得 Type
我們傳入物件,由物件取得Type (obj.GetType())。''' <summary> ''' 由物件取得型別 ''' </summary> ''' <param name="objArray">物件陣列</param> Sub ShowTypeFromObject(objArray() As Object) For Each obj In objArray Dim objType As Type = obj.GetType() Console.WriteLine("Object取得:") Console.WriteLine("Type: {0}", objType.Name) Console.WriteLine() ShwoTypeAttributes(objType) Next End Sub
這裡面還使用另一個副程式 ShwoTypeAttributes(),也很簡單,我們取的物件型別(ObjType)後,在從物件型別(ObjType)裡顯示相關屬性。這裡會使用到後面文章的程式碼,我先寫出來,後面文章再來解釋。我們先專注在取得型別這件事情上面。
#Region "由物件取得型別後,顯示其他資訊" ''' <summary> ''' 由物件取得型別後,額外顯示型別屬性 ''' </summary> ''' <param name="objType">物件</param> Sub ShwoTypeAttributes(ByVal objType As Object) Dim type As Type = objType.GetType() GetTypeAttribute(type) ' 此為後面文章副程式,後面再來解釋 ShowCustomAttribute(type) ' 此為後面文章副程式,後面再來解釋 ShowTypeGetxxx(type) End Sub ''' <summary> ''' 由物件取得型別後,額外顯示相關屬性 ''' </summary> ''' <param name="type">Type (型別)</param> Sub GetTypeAttribute(type As Type) Console.WriteLine("型別的屬性") Console.WriteLine("Assembly : {0}", type.Assembly) Console.WriteLine("AQN : {0}", type.AssemblyQualifiedName) Console.WriteLine("Attributes: {0}", type.Attributes) Console.WriteLine("BaseType: {0}", type.BaseType) Console.WriteLine("FullName: {0}", type.FullName) Console.WriteLine("HasElementType: {0}", type.HasElementType) Console.WriteLine("IsAbstract: {0}", type.IsAbstract) Console.WriteLine("IsByRef: {0}", type.IsByRef) Console.WriteLine("IsClass: {0}", type.IsClass) Console.WriteLine("IsEnum: {0}", type.IsEnum) Console.WriteLine("IsGenericType: {0}", type.IsGenericType) Console.WriteLine("IsInterface: {0}", type.IsInterface) Console.WriteLine("IsMarshalByRef: {0}", type.IsMarshalByRef) Console.WriteLine("IsNotPublic: {0}", type.IsNotPublic) Console.WriteLine("IsPrimitive: {0}", type.IsPrimitive) Console.WriteLine("IsPublic: {0}", type.IsPublic) Console.WriteLine("IsSealed: {0}", type.IsSealed) Console.WriteLine("IsValueType: {0}", type.IsValueType) Console.WriteLine("IsVisible: {0}", type.IsVisible) Console.WriteLine("Module: {0}", type.Module) Console.WriteLine("Name: {0}", type.Name) Console.WriteLine("Namespace: {0}", type.Namespace) Console.WriteLine() Console.ReadLine() End Sub #End Region
為了讓範例能動,我先寫出來 ShowCustomAttribute(), ShowTypeGetxxx() … 相關副程式,後面文章再來解釋。我們先專注在取得型別這件事情上面。
''' <summary> ''' 由傳入參數,顯示相關型別相關屬性 ''' </summary> ''' <param name="type">Type (型別)</param> Sub ShowCustomAttribute(type As Type) Console.WriteLine("取得類別屬性:") For Each attr As Attribute In type.GetCustomAttributes(True) Console.WriteLine(" {0}", attr.GetType.Name) Next Console.WriteLine() End Sub #Region "顯示型別相關 Getxxx 方法" ''' <summary> ''' 呼叫型別相關 Getxxx 測試方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Sub ShowTypeGetxxx(type As Type) ShowGetProperties(type) ShowGetNestedTypes(type) ShowGetMembers(type) ShowGetConstructors(type) ShowGetEvent(type) ShowGetFields(type) ShowGetMethods(type) End Sub ''' <summary> ''' 簡單測試及顯示型別的屬性(Properties) ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Private Sub ShowGetProperties(type As Type) Console.WriteLine("取得型別Properties") For Each pi As PropertyInfo In type.GetProperties Console.WriteLine("{0}", pi.Name) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示型別的NestedTypes ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Private Sub ShowGetNestedTypes(type As Type) Console.WriteLine("取得型別NestedTypes") For Each gnt As Type In type.GetNestedTypes Console.WriteLine("{0}", gnt.Name) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示型別 GetMembers() 方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Private Sub ShowGetMembers(type As Type) Console.WriteLine("取得型別Members") For Each mi As MemberInfo In type.GetMembers() Console.WriteLine(" Member的 Type 及 名稱") Console.WriteLine(" {0}:{1}", mi.MemberType, mi.Name) ShowMemberType(mi) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示MemberInfo裡MemberType成員,目前只讓 ShowGetMembers 呼叫 ''' </summary> ''' <param name="mi">MemberInfo物件</param> Private Sub ShowMemberType(mi As MemberInfo) ' MemberInfo 可藉由 MemberTypes 來判斷出型別的不同成員,注意,都是public。 ' 簡單測試 MemberTypes.Property Select Case mi.MemberType Case MemberTypes.Constructor Case MemberTypes.Custom Case MemberTypes.Event Case MemberTypes.Field Case MemberTypes.Method Case MemberTypes.NestedType Case MemberTypes.Property Dim pi As PropertyInfo = CType(mi, PropertyInfo) Console.WriteLine(" Property Type: {0}", pi.PropertyType.Name) Case MemberTypes.TypeInfo Case MemberTypes.All Case Else Console.WriteLine("什麼!完全沒有符合的成員!") End Select End Sub ''' <summary> ''' 簡單測試及顯示型別 GetConstructors 方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Sub ShowGetConstructors(type As Type) Console.WriteLine("取得型別Constructors") For Each ci As ConstructorInfo In type.GetConstructors Console.WriteLine(" IsSecuritySafeCritical: {0}", ci.IsSecuritySafeCritical) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示型別 GetEvents 方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Sub ShowGetEvent(type As Type) Console.WriteLine("取得型別Events") For Each ei As EventInfo In type.GetEvents Console.WriteLine(" DeclaringType: {0}", ei.DeclaringType) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示型別 GetFields 方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Sub ShowGetFields(type As Type) Console.WriteLine("取得型別Fields") For Each fi As FieldInfo In type.GetFields Console.WriteLine(" FieldType: {0}", fi.FieldType) Next Console.WriteLine() Console.ReadLine() End Sub ''' <summary> ''' 簡單測試及顯示型別 GetMethods 方法 ''' </summary> ''' <param name="type">型別 (即Type) 物件</param> Sub ShowGetMethods(type As Type) Console.WriteLine("取得型別Methods") For Each mi As MethodInfo In type.GetMethods Console.WriteLine("Method: {0}, IsPublic: {1}", mi.GetBaseDefinition.Name, mi.IsPublic) Next Console.WriteLine() Console.ReadLine() End Sub #End Region
主程式與前二個不同,我們必須傳入一個物件陣列,這個陣列的內容你可以自訂。我傳入四個 Object,分別為 String, Int32, Double, Boolean。
Dim t() As Object = {"String", 1, 0.5, True} ShowTypeFromObject(t) ' String, Int32, Double, Boolean
我們來看執行結果,由於結果很長,我只先貼上 String 的結果。
Object取得: Type: String 型別的屬性 Assembly : mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 AQN : System.RuntimeType, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Attributes: AutoLayout, AnsiClass, Class, Serializable, BeforeFieldInit BaseType: System.Type FullName: System.RuntimeType HasElementType: False IsAbstract: False IsByRef: False IsClass: True IsEnum: False IsGenericType: False IsInterface: False IsMarshalByRef: False IsNotPublic: True IsPrimitive: False IsPublic: False IsSealed: False IsValueType: False IsVisible: False Module: CommonLanguageRuntimeLibrary Name: RuntimeType Namespace: System 取得類別屬性: SerializableAttribute 取得型別Properties Module Assembly TypeHandle DeclaringMethod BaseType UnderlyingSystemType FullName ... 取得型別NestedTypes Member的 Type 及 名稱 Method:GetMethod Member的 Type 及 名稱 Method:GetMethod Member的 Type 及 名稱 Method:GetMethods Member的 Type 及 名稱 Method:GetField Member的 Type 及 名稱 Method:GetFields ... Member的 Type 及 名稱 Property:Module Property Type: Module Member的 Type 及 名稱 Property:Assembly Property Type: Assembly Member的 Type 及 名稱 Property:TypeHandle Property Type: RuntimeTypeHandle Member的 Type 及 名稱 Property:DeclaringMethod Property Type: MethodBase ... 取得型別Constructors 取得型別Events 取得型別Fields 取得型別Methods Method: get_Module, IsPublic: True Method: get_Assembly, IsPublic: True Method: get_TypeHandle, IsPublic: True Method: get_DeclaringMethod, IsPublic: True Method: get_BaseType, IsPublic: True ...
這裡先不急,相關副程式我們後面的慢慢說,但從這裡我們也知道一件事,取得型別(Type)後,我們還能再往下進行很多事,了解這些層級關係會對我們學習反映( Reflection )很有幫助。
VB GetType() 取得 Type
相較於前面的範例,使用VB本身的GetType()來取得Type(型別),是比較簡單的。''' <summary> ''' 由VB本身的 GetType() 來取得型別 ''' </summary> Sub ShowTypeFromVBGetType() Dim vbtype As Type = GetType(Int32) Console.WriteLine("VB GetType取得:") Console.WriteLine("Type: {0}", vbtype.FullName) Console.WriteLine() End Sub
這個 ShowTypeFromVBGetType() 副程式比較沒有彈性,GetType(Int32) 我是寫死的。沒有傳入參考再依參數來決定來取得Type,不過上面寫太多了,有點累了,這就交給你們自行修改。主程式直接呼叫 ShowTypeFromVBGetType() 使用即可。
我們來看執行結果:
VB GetType取得: Type: System.Int32
如果你想看其他結果,你使能用 Object 取得 Type 裡的副程式,這裡我只是最簡易的顯示一個 FullName。
結論
以上我們就「取得型別(Type)」這件事,進行很長的討論。取得了型別後,接下來,我們就可以做很多事。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。