跳轉到內容

BlitzMax/模組/BASIC/反射

來自華夏公益教科書,開放的書籍,為開放的世界

BlitzMax 為執行時反射提供有限支援。

使用反射,程式可以在執行時“檢查”物件和型別。你可以確定物件或型別中包含的欄位和方法,設定和獲取物件欄位並呼叫物件方法。

要使用反射,你首先需要一個 TTypeId 物件。TTypeId 物件對應於 BlitzMax 使用者定義的型別,程式中的每個使用者定義的型別都有一個 TTypeId 物件。還有一些 TTypeId 物件用於“基本”型別 - 位元組、短整型、整型、長整型、浮點型、雙精度型和字串。TTypeId 物件由TTypeId.ForNameTTypeId.ForObject 函式返回。

獲得 TTypeId 物件後,可以使用EnumFieldsEnumMethods 方法檢查使用者定義型別的欄位和方法。這些方法返回TFieldTMethod 物件,它們描述了型別內的欄位和方法。例如

Strict

Type TMyType
Field x,y,z
End Type

Local id:TTypeId=TTypeId.ForName( "TMyType" )

For Local fld:TField=EachIn id.EnumFields()
Print fld.Name()+":"+fld.TypeId().Name()
Next

這個簡單的程式將列印“x:Int”、“y:Int”和“z:Int” - TMyType 內欄位的名稱和型別。請注意,這是在沒有實際建立新的 TMyType 的情況下完成的。

以下示例設定了物件的欄位

Strict

Type TMyType
Field x,y,z
End Type

Local obj:TMyType=New TMyType
Local id:TTypeId=TTypeId.ForObject( obj )

For Local fld:TField=EachIn id.EnumFields()
fld.Set obj,String( Rand(10) )
Next

Print obj.x+","+obj.y+","+obj.z

在這種情況下,我們需要一個實際的 TMyType 例項,否則我們將無法設定欄位!另外,我們使用了 TTypeId.ForObject 而不是 TTypeId.ForName 來獲取一個 TTypeId。雖然在這種情況下可以使用 TTypeId.ForName 來達到相同的結果,但一般情況下我們可能不知道物件的具體型別,因此我們也不知道其型別名稱。

還要注意,實際設定欄位的程式碼使用的是 String( Rand(10) )。這是因為Set 方法接受一個物件 - 但我們的欄位是整型!BlitzMax 反射透過使用字串來表示數值型別來解決這個問題。相同的規則適用於Get 方法。任何數值欄位都將作為字串返回,如果需要,你必須將其轉換為相應的型別。

最後,讓我們呼叫物件方法

Strict

Type TMyType
Method Update( t# )
Print "TMyType.Update:"+t
End Method
End Type

Local obj:TMyType=New TMyType
Local id:TTypeId=TTypeId.ForObject( obj )

Local update:TMethod=id.FindMethod( "Update" )

update.Invoke obj,[String( .25 )]

這個示例使用FindMethod 來定位型別方法,使用Invoke 來呼叫它。方法的引數包含在一個物件陣列中,同樣,浮點型引數也被轉換為字串。

除了 TTypeId、TField 和 TMethod 型別之外,BlitzMax 反射模組還聲明瞭一些全域性 TTypeId 物件

  • ByteTypeId
  • ShortTypeId
  • IntTypeId
  • LongTypeId
  • FloatTypeId
  • DoubleTypeId
  • StringTypeId
  • ObjectTypeId

這些可以代替相應的 TTypeId.ForName 呼叫。例如,TTypeId.ForName( "Int" )IntTypeId 將返回同一個物件。

全域性變數

[編輯 | 編輯原始碼]

ByteTypeId

[編輯 | 編輯原始碼]

Global ByteTypeId:TTypeId=New TTypeId.Init( "Byte",1 )

描述: 基本位元組型別

ShortTypeId

[編輯 | 編輯原始碼]

Global ShortTypeId:TTypeId=New TTypeId.Init( "Short",2 )

描述: 基本短整型型別

IntTypeId

[編輯 | 編輯原始碼]

Global IntTypeId:TTypeId=New TTypeId.Init( "Int",4 )

描述: 基本整型型別

LongTypeId

[編輯 | 編輯原始碼]

Global LongTypeId:TTypeId=New TTypeId.Init( "Long",8 )

描述: 基本長整型型別

FloatTypeId

[編輯 | 編輯原始碼]

Global FloatTypeId:TTypeId=New TTypeId.Init( "Float",4 )

描述: 基本浮點型型別

DoubleTypeId

[編輯 | 編輯原始碼]

Global DoubleTypeId:TTypeId=New TTypeId.Init( "Double",8 )

描述: 基本雙精度型型別

StringTypeId

[編輯 | 編輯原始碼]

Global StringTypeId:TTypeId=New TTypeId.Init( "String",4,bbRefStringClass() )

描述: 基本字串型別

ObjectTypeId

[編輯 | 編輯原始碼]

Global ObjectTypeId:TTypeId=New TTypeId.Init( "Object",4,bbRefObjectClass() )

描述: 基本物件型別

ArrayTypeId

[編輯 | 編輯原始碼]

Global ArrayTypeId:TTypeId=New TTypeId.Init( "Null[]",4,bbRefArrayClass() )

描述: 基本陣列型別

型別成員 - 欄位或方法。

方法
  • 名稱
  • TypeId
  • 元資料

TMember: 方法

[編輯 | 編輯原始碼]
名稱

Method Name$()

描述: 獲取成員名稱

TypeId

Method TypeId:TTypeId()

描述: 獲取成員型別

元資料

Method MetaData$( key$="" )

描述: 獲取成員元資料

型別欄位

方法
  • 獲取
  • GetInt
  • GetLong
  • GetFloat
  • GetDouble
  • GetString
  • 設定
  • SetInt
  • SetLong
  • SetFloat
  • SetDouble
  • SetString

TField: 方法

[編輯 | 編輯原始碼]
獲取

Method Get:Object( obj:Object )

描述: 獲取欄位值

GetInt

Method GetInt:Int( obj:Object )

描述: 獲取整型欄位值

GetLong

方法 GetLong:Long( obj:Object )

描述: 獲取長整型欄位值

GetFloat

方法 GetFloat:Float( obj:Object )

描述: 獲取浮點型欄位值

GetDouble

方法 GetDouble:Double( obj:Object )

描述: 獲取雙精度浮點型欄位值

GetString

方法 GetString$( obj:Object )

描述: 獲取字串欄位值

設定

方法 Set( obj:Object,value:Object )

描述: 設定欄位值

SetInt

方法 SetInt( obj:Object,value:Int )

描述: 設定整型欄位值

SetLong

方法 SetLong( obj:Object,value:Long )

描述: 設定長整型欄位值

SetFloat

方法 SetFloat( obj:Object,value:Float )

描述: 設定浮點型欄位值

SetDouble

方法 SetDouble( obj:Object,value:Double )

描述: 設定雙精度浮點型欄位值

SetString

方法 SetString( obj:Object,value$ )

描述: 設定字串欄位值

型別 方法

方法
  • ArgTypes
  • Invoke

TMethod: 方法

[編輯 | 編輯原始碼]
ArgTypes

方法 ArgTypes:TTypeId[]()

描述: 獲取方法引數型別

Invoke

方法 Invoke:Object( obj:Object,args:Object[] )

描述: 呼叫方法

型別 id

方法
  • 名稱
  • 元資料
  • SuperType
  • ArrayType
  • ElementType
  • ExtendsType
  • DerivedTypes
  • NewObject
  • Fields
  • 方法
  • FindField
  • FindMethod
  • EnumFields
  • EnumMethods
  • NewArray
  • ArrayLength
  • ArrayDimensions
  • GetArrayElement
  • SetArrayElement
函式
  • ForName
  • ForObject
  • EnumTypes

TTypeId: 方法

[編輯 | 編輯原始碼]
名稱

Method Name$()

描述: 獲取型別的名稱

元資料

Method MetaData$( key$="" )

描述: 獲取型別元資料

SuperType

方法 SuperType:TTypeId()

描述: 獲取父型別

ArrayType

方法 ArrayType:TTypeId(dims:Int = 1)

描述: 獲取陣列型別

ElementType

方法 ElementType:TTypeId()

描述: 獲取元素型別

ExtendsType

方法 ExtendsType( typeId:TTypeId )

描述: 判斷型別是否繼承自某個型別

DerivedTypes

方法 DerivedTypes:TList()

描述: 獲取派生型別列表

NewObject

方法 NewObject:Object()

描述: 建立一個新物件

Fields

方法 Fields:TList()

描述: 獲取欄位列表

資訊: 僅返回該型別中宣告的欄位,不包括父型別中的欄位。

方法

方法 Methods:TList()

描述: 獲取方法列表

資訊: 僅返回該型別中宣告的方法,不包括父型別中的方法。

FindField

方法 FindField:TField( name$ )

描述: 按名稱查詢欄位

資訊: 在型別層次結構中搜索名為 name 的欄位。

FindMethod

方法 FindMethod:TMethod( name$ )

描述: 按名稱查詢方法

資訊: 在型別層次結構中搜索名為 name 的方法。

EnumFields

方法 EnumFields:TList( list:TList=Null )

描述: 列舉所有欄位

資訊: 返回型別層次結構中所有欄位的列表

EnumMethods

方法 EnumMethods:TList( list:TList=Null )

描述: 列舉所有方法

資訊: 返回型別層次結構中所有方法的列表 - TODO: 處理覆蓋方法!

NewArray

方法 NewArray:Object( length, dims:Int[] = Null )

描述: 建立一個新陣列

ArrayLength

方法 ArrayLength( array:Object, dim:Int = 0 )

描述: 獲取陣列長度

ArrayDimensions

方法 ArrayDimensions:Int( array:Object )

描述: 獲取維度數量

GetArrayElement

方法 GetArrayElement:Object( array:Object,index )

描述: 獲取陣列元素

SetArrayElement

方法 SetArrayElement( array:Object,index,value:Object )

描述: 設定陣列元素

TTypeId: 函式

[編輯 | 編輯原始碼]
ForName

函式 ForName:TTypeId( name$ )

描述: 按名稱獲取型別

ForObject

函式 ForObject:TTypeId( obj:Object )

描述: 按物件獲取型別

EnumTypes

函式 EnumTypes:TList()

描述: 獲取所有型別的列表

華夏公益教科書