TValue是Delphi的RTTI系統的重要類型。 經過摸索,發現TValue功能強大,可以實現很多功能。本文章中所有程序采用XE3運行通過。
一、TValue結構
TValue定義在System.Rtti.pas
TValue = ;
TValue提供了一些系列方法,幾乎都是操作FData.
TValueData描述如下:
TValueData = //// FHeapData doubled storage // the values: FTypeInfo couldn //// would be // FValueData different: interfaces are always // a reference Integer ;
TValueData是一個結構體,TValueData可以存儲任何類型的數據,經過TValue的方法可以與任何類型進行轉換:
TValue = // Low-level Make(ABuffer: Pointer; ATypeInfo: PTypeInfo; Result: TValue); MakeWithoutCopy(ABuffer: Pointer; ATypeInfo: PTypeInfo; Result: TValue); Make(AValue: NativeInt; ATypeInfo: PTypeInfo; Result: TValue); // Low-level DataSize: Integer // If internal data something // reference *without*;
通過調用Make(...),將任意類型數據轉換為TValue
通過調用ExtractRawData(...), ExtractRawDataNoCopy(...)將TValue轉換為任意數據類型,兩者區別是ExtractRawDataNoCopy轉換時在堆中申請內存的數據,而ExtractRawData是安全的。
GetReferenceToRawData返回數據的指針,也是堆內存的指針。
二、類型轉換為TValue
下面例子測試Integer和TRect:
IntData := TValue.Make(@IntData,TypeInfo(Integer),IntValue); //Integer類型也可以直接調用 IntValue := RecData.Left := RecData.Right := .
)
三、TValue轉換到類型
在反序列化(反持久化)時,如果知道數據類型,可以調用下面的方法生成一個與此類型相應的TValue空記錄:
TValue.Make(,TypeInfoVar,OutputTValue);
通過ExtractRawData,可以將TValue數據直接轉換某類型數據:
RecData.Left := RecData.Right := TValue.Make(@RecData,TypeInfo(TRect),RecValue); // RecValue.ExtractRawData(@RecDataOut); // .
四、通過TValue的訪問類型的成員變量
TValue轉換自某個類型後,可以使用的GetReferenceToRawData()獲取數據指針,通過調用SetValue和GetValue讀寫
某個成員的值。
Ctx := // TValue.Make( // Ctx.GetType(TypeInfo(TRect)).GetField().SetValue(RecValue.GetReferenceToRawData, Ctx.GetType(TypeInfo(TRect)).GetField().SetValue(RecValue.GetReferenceToRawData, // .
五、泛型轉換函數
我們上面的例子,通過調用Make函數來轉換成TValue,以及通過ExtractRawData轉換成需要的類型,
Delphi還提供了泛型轉換函數,可以指定已知的類型,直接進行轉換:
From<T>( AsType<T> IsType<T> TryAsType<T>( Cast<T>: TValue; ;
看下面的例子:
RecData.Left := RecData.Right := RecValue := TValue.From<TRect>(RecData); // Writeln(RecValue.IsType<TRect> RecDataOut := RecValue.AsType<TRect>; // .
六、數組
如果TValue轉換自數組類型,則可以調用一下方法:
SetArrayElement(Index: Integer; AValue: TValue);
如果用下面的方式定義數組,則不支持轉換到TValue:
Integer;
我可以先定義數組類型後,再定義變量,則可以轉換到TValue:
= //<Integer>; //在 System.pas 定義: TArray<T> = T;
七、Variant
Variant與TValue的轉換容易產生混淆,調用TValue.FromVariant(),並不是將Varaint轉換為TValue:
vExample := Value := TValue.FromVariant(vExample); // vExample := Value := .
Hello World
如果希望將Variant轉換為TValue,可以使用這個方法:
vExample := Value := TValue.From<> Writeln(value.AsType<variant> vExample := Value := TValue.From<> Writeln(value.AsType<variant> .
Hello World