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)」這件事,進行很長的討論。取得了型別後,接下來,我們就可以做很多事。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。