前面,我們已經學會了從組件(Assembly)、模組(Module)取得資訊,也試著從 AssemblyInfo.vb 取得屬性。還有那一句超重點:「
組件(Assembly)包含模組(Module),模組包含型別(Type),型別包含成員。」今天我們進行第三個重點,
型別(Type),進入之前,我們先看一點點 MSDN 的資料。
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 開頭為一類
Getxxx 所代表的是「
取得」,取得此型別(Type)的 xxx,從建構函式、自訂屬性、公用欄位、介面、公用成員、公用方法、公用屬性 …。反正你想得到的一切,Getxxx 都能幫你取得。
Isxxx 所代表的是「
判斷」,你能拿 Isxxx 來判斷此型別(Type),例如,Type.IsArray() 判斷是否為陣列。
當我們取得型別(Type)後,我們就能夠透過 Getxxx 或 Isxxx 來取得與判斷此型別。所以,回過頭來,我們要來介紹,取得取得型別的4種方法。
取得型別的4種方法
取得型別的4種方法分別是:
- Assembly 取得 Type
- Module 取得 Type
- Object 取得 Type
- VB GetType() 取得 Type
以下一一介紹。
Assembly 取得 Type
ShowTypeFromAssembly() 副程式,由傳入的組件需得型別資料。
05 | Sub ShowTypeFromAssembly(asm As Assembly ) |
06 | Dim asmTypes() As Type = asm.GetTypes() |
07 | Console.WriteLine( "組件取得:" ) |
08 | For Each asmType In asmTypes |
09 | Console.WriteLine( "Type: {0}" , asmType.Name) |
我們來看主程式:
1 | Dim d As Assembly = Assembly .GetExecutingAssembly() |
我們先取得正在執行的組件,指後傳入副程式顯示型別資料。
我們得到的結果:
組件取得:
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後的程式碼(注意,此程式碼無法執行,此為原型程式碼)
1 | myListOfInstances = (From file In Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins" ), "*.dll" ) |
2 | Let a = Assembly .LoadFrom(file) |
4 | Where Not t.IsAbstract AndAlso t.BaseType = GetType (MyBaseClass) |
5 | Select CType (MyBaseClass,Activator.CreateInstance(t, credentials))).ToList() |
有問題,請參考原文章。
Module 取得 Type
與 Assembly 取得 Type 不同,上面是傳入 Assembly 直接取得 Type,而在 ShowTypeFromModule() 副程式中,我們是傳入 Assembly,先由 Assembly 取得 Module 後,在從 Module 裡取得 Type。
05 | Sub ShowTypeFromModule(asm As Assembly ) |
06 | Dim mods() As [ Module ] = asm.GetModules() |
07 | Dim m As [ Module ] = mods(0) |
08 | Dim modTypes() As Type = m.GetTypes() |
10 | Console.WriteLine( "模組取得:" ) |
11 | For Each modType In modTypes |
12 | Console.WriteLine( "Type: {0}" , modType.Name) |
主程式和上面一樣,傳入 Assembly 的 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())。
05 | Sub ShowTypeFromObject(objArray() As Object ) |
06 | For Each obj In objArray |
07 | Dim objType As Type = obj. GetType () |
08 | Console.WriteLine( "Object取得:" ) |
09 | Console.WriteLine( "Type: {0}" , objType.Name) |
11 | ShwoTypeAttributes(objType) |
這裡面還使用另一個副程式 ShwoTypeAttributes(),也很簡單,我們取的物件型別(ObjType)後,在從物件型別(ObjType)裡顯示相關屬性。這裡會使用到後面文章的程式碼,我先寫出來,後面文章再來解釋。我們先
專注在取得型別這件事情上面。
01 | #Region "由物件取得型別後,顯示其他資訊" |
07 | Sub ShwoTypeAttributes( ByVal objType As Object ) |
08 | Dim type As Type = objType. GetType () |
09 | GetTypeAttribute(type) |
11 | ShowCustomAttribute(type) |
20 | Sub GetTypeAttribute(type As Type) |
21 | Console.WriteLine( "型別的屬性" ) |
22 | Console.WriteLine( "Assembly : {0}" , type. Assembly ) |
23 | Console.WriteLine( "AQN : {0}" , type.AssemblyQualifiedName) |
24 | Console.WriteLine( "Attributes: {0}" , type.Attributes) |
25 | Console.WriteLine( "BaseType: {0}" , type.BaseType) |
26 | Console.WriteLine( "FullName: {0}" , type.FullName) |
27 | Console.WriteLine( "HasElementType: {0}" , type.HasElementType) |
28 | Console.WriteLine( "IsAbstract: {0}" , type.IsAbstract) |
29 | Console.WriteLine( "IsByRef: {0}" , type.IsByRef) |
30 | Console.WriteLine( "IsClass: {0}" , type.IsClass) |
31 | Console.WriteLine( "IsEnum: {0}" , type.IsEnum) |
32 | Console.WriteLine( "IsGenericType: {0}" , type.IsGenericType) |
33 | Console.WriteLine( "IsInterface: {0}" , type.IsInterface) |
34 | Console.WriteLine( "IsMarshalByRef: {0}" , type.IsMarshalByRef) |
35 | Console.WriteLine( "IsNotPublic: {0}" , type.IsNotPublic) |
36 | Console.WriteLine( "IsPrimitive: {0}" , type.IsPrimitive) |
37 | Console.WriteLine( "IsPublic: {0}" , type.IsPublic) |
38 | Console.WriteLine( "IsSealed: {0}" , type.IsSealed) |
39 | Console.WriteLine( "IsValueType: {0}" , type.IsValueType) |
40 | Console.WriteLine( "IsVisible: {0}" , type.IsVisible) |
41 | Console.WriteLine( "Module: {0}" , type. Module ) |
42 | Console.WriteLine( "Name: {0}" , type.Name) |
43 | Console.WriteLine( "Namespace: {0}" , type. Namespace ) |
為了讓範例能動,我先寫出來 ShowCustomAttribute(), ShowTypeGetxxx() … 相關副程式,後面文章再來解釋。我們先
專注在取得型別這件事情上面。
005 | Sub ShowCustomAttribute(type As Type) |
006 | Console.WriteLine( "取得類別屬性:" ) |
007 | For Each attr As Attribute In type.GetCustomAttributes( True ) |
008 | Console.WriteLine( " {0}" , attr. GetType .Name) |
013 | #Region "顯示型別相關 Getxxx 方法" |
019 | Sub ShowTypeGetxxx(type As Type) |
020 | ShowGetProperties(type) |
021 | ShowGetNestedTypes(type) |
023 | ShowGetConstructors(type) |
033 | Private Sub ShowGetProperties(type As Type) |
034 | Console.WriteLine( "取得型別Properties" ) |
035 | For Each pi As PropertyInfo In type.GetProperties |
036 | Console.WriteLine( "{0}" , pi.Name) |
046 | Private Sub ShowGetNestedTypes(type As Type) |
047 | Console.WriteLine( "取得型別NestedTypes" ) |
048 | For Each gnt As Type In type.GetNestedTypes |
049 | Console.WriteLine( "{0}" , gnt.Name) |
059 | Private Sub ShowGetMembers(type As Type) |
060 | Console.WriteLine( "取得型別Members" ) |
061 | For Each mi As MemberInfo In type.GetMembers() |
062 | Console.WriteLine( " Member的 Type 及 名稱" ) |
063 | Console.WriteLine( " {0}:{1}" , mi.MemberType, mi.Name) |
074 | Private Sub ShowMemberType(mi As MemberInfo) |
077 | Select Case mi.MemberType |
078 | Case MemberTypes.Constructor |
079 | Case MemberTypes.Custom |
080 | Case MemberTypes. Event |
081 | Case MemberTypes.Field |
082 | Case MemberTypes.Method |
083 | Case MemberTypes.NestedType |
084 | Case MemberTypes. Property |
085 | Dim pi As PropertyInfo = CType (mi, PropertyInfo) |
086 | Console.WriteLine( " Property Type: {0}" , pi.PropertyType.Name) |
087 | Case MemberTypes.TypeInfo |
090 | Console.WriteLine( "什麼!完全沒有符合的成員!" ) |
098 | Sub ShowGetConstructors(type As Type) |
099 | Console.WriteLine( "取得型別Constructors" ) |
100 | For Each ci As ConstructorInfo In type.GetConstructors |
101 | Console.WriteLine( " IsSecuritySafeCritical: {0}" , ci.IsSecuritySafeCritical) |
111 | Sub ShowGetEvent(type As Type) |
112 | Console.WriteLine( "取得型別Events" ) |
113 | For Each ei As EventInfo In type.GetEvents |
114 | Console.WriteLine( " DeclaringType: {0}" , ei.DeclaringType) |
124 | Sub ShowGetFields(type As Type) |
125 | Console.WriteLine( "取得型別Fields" ) |
126 | For Each fi As FieldInfo In type.GetFields |
127 | Console.WriteLine( " FieldType: {0}" , fi.FieldType) |
137 | Sub ShowGetMethods(type As Type) |
138 | Console.WriteLine( "取得型別Methods" ) |
139 | For Each mi As MethodInfo In type.GetMethods |
140 | Console.WriteLine( "Method: {0}, IsPublic: {1}" , mi.GetBaseDefinition.Name, mi.IsPublic) |
主程式與前二個不同,我們必須傳入一個物件陣列,這個陣列的內容你可以自訂。我傳入四個 Object,分別為 String, Int32, Double, Boolean。
1 | Dim t() As Object = { "String" , 1, 0.5, True } |
我們來看執行結果,由於結果很長,我只先貼上 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(型別),是比較簡單的。
4 | Sub ShowTypeFromVBGetType() |
5 | Dim vbtype As Type = GetType (Int32) |
6 | Console.WriteLine( "VB GetType取得:" ) |
7 | Console.WriteLine( "Type: {0}" , vbtype.FullName) |
這個 ShowTypeFromVBGetType() 副程式比較沒有彈性,
GetType(Int32) 我是寫死的。沒有傳入參考再依參數來決定來取得Type,不過上面寫太多了,有點累了,這就交給你們自行修改。主程式直接呼叫 ShowTypeFromVBGetType() 使用即可。
我們來看執行結果:
VB GetType取得:
Type: System.Int32
如果你想看其他結果,你使能用 Object 取得 Type 裡的副程式,這裡我只是最簡易的顯示一個 FullName。
結論
以上我們就「取得型別(Type)」這件事,進行很長的討論。取得了型別後,接下來,我們就可以做很多事。
參考資料
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。