|
一、TValue结构
TValue定义在System.Rtti.pas
通过调用Make(...),将任意类型数据转换为TValue 通过调用ExtractRawData(...), ExtractRawDataNoCopy(...)将TValue转换为任意数据类型,两者区别是ExtractRawDataNoCopy转换时在堆中申请内存的数据,而ExtractRawData是安全的。 GetReferenceToRawData返回数据的指针,也是堆内存的指针。
二、类型转换为TValue
program Project1; {$APPTYPE CONSOLE} uses SysUtils, Windows, TypInfo,Rtti;
var IntData : Integer; IntValue : TValue;
RecData : TRect; RecValue : TValue;
begin IntData := 1234; TValue.Make(@IntData,TypeInfo(Integer),IntValue); //Integer类型也可以直接调用 IntValue := IntData; 这里演示TValue.Make Writeln(IntValue.ToString); RecData.Left := 10; RecData.Right := 20; TValue.Make(@RecData,TypeInfo(TRect),RecValue); Writeln(RecValue.ToString); readln; end.
三、TValue转换到类型
在反序列化(反持久化)时,如果知道数据类型,可以调用下面的方法生成一个与此类型相应的TValue空记录:
TValue.Make(nil,TypeInfoVar,OutputTValue); 通过ExtractRawData,可以将TValue数据直接转换某类型数据:
program Project2; {$APPTYPE CONSOLE} uses SysUtils, Windows, TypInfo,Rtti;
var RecData : TRect; RecDataOut : TRect; RecValue : TValue;
begin RecData.Left := 10; RecData.Right := 20; TValue.Make(@RecData,TypeInfo(TRect),RecValue); //将TRect结构的RecData转换为TValue类型的RecValue
RecValue.ExtractRawData(@RecDataOut); //将TValue 结构数据转换成TRect类型数据 Writeln(RecDataOut.Left); Writeln(RecDataOut.Right);
readln; end.
四、通过TValue的访问类型的成员变量
TValue转换自某个类型后,可以使用的GetReferenceToRawData()获取数据指针,通过调用SetValue和GetValue读写 某个成员的值。
program Project3; {$APPTYPE CONSOLE} uses SysUtils, Windows, TypInfo,Rtti;
var RecData : TRect; RecValue : TValue; Ctx : TRttiContext;
begin Ctx := TRttiContext.Create; // 创建空的、与TRect对应的TValue结构体, TValue.Make(nil,TypeInfo(TRect),RecValue); // 设置 Left 、 Right 成员变量值,使用TValue中成员变量的地址指针 Ctx.GetType(TypeInfo(TRect)).GetField('Left').SetValue(RecValue.GetReferenceToRawData,10); Ctx.GetType(TypeInfo(TRect)).GetField('Right').SetValue(RecValue.GetReferenceToRawData,20); // 转换为TRect结构体数据 RecValue.ExtractRawData(@RecData); Writeln(RecData.Left); Writeln(RecData.Right); readln; Ctx.Free; end.
五、泛型转换函数
我们上面的例子,通过调用Make函数来转换成TValue,以及通过ExtractRawData转换成需要的类型, Delphi还提供了泛型转换函数,可以指定已知的类型,直接进行转换:
class function From<T>(const Value: T): TValue; static;
function AsType<T>: T;
function IsType<T>: Boolean;
function TryAsType<T>(out AResult: T): Boolean;
function Cast<T>: TValue; overload;
program Project4; {$APPTYPE CONSOLE} uses SysUtils, Windows, TypInfo,Rtti;
var RecData : TRect; RecDataOut : TRect; RecValue : TValue; begin RecData.Left := 10; RecData.Right := 20;
RecValue := TValue.From<TRect>(RecData); //直接转换成 TValue
Writeln(RecValue.IsType<TRect>);
RecDataOut := RecValue.AsType<TRect>; //TValue直接转换成TRect
Writeln(RecDataOut.Left); Writeln(RecDataOut.Right); readln; end.
六、数组
如果TValue转换自数组类型,则可以调用一下方法:
function GetArrayLength: Integer;
function GetArrayElement(Index: Integer): TValue;
procedure SetArrayElement(Index: Integer; const AValue: TValue); 我可以先定义数组类型后,再定义变量,则可以转换到TValue:
type TIntArray = array of Integer; var IntArray : TIntArray; // 或者 IntArray : TArray<Integer>; //在 System.pas 定义: TArray<T> = array of T;
七、Variant
Variant与TValue的转换容易产生混淆,调用TValue.FromVariant(),并不是将Varaint转换为TValue:
program Project5; {$APPTYPE CONSOLE} uses SysUtils, TypInfo,Rtti;
var vExample : Variant; Value : TValue; begin vExample := 'Hello World'; Value := TValue.FromVariant(vExample); // writeln(GetEnumName(TypeInfo(TTypeKind),Ord(Value.Kind))); Writeln(value.ToString);
vExample := 1234; Value := TValue.FromVariant(vExample); writeln(GetEnumName(TypeInfo(TTypeKind),Ord(Value.Kind))); Writeln(value.ToString);
readln; end.
如果希望将Variant转换为TValue,可以使用这个方法:
program Project6; {$APPTYPE CONSOLE} uses SysUtils, TypInfo,Rtti;
var vExample : Variant; Value : TValue; begin vExample := 'Hello World'; Value := TValue.From<variant>(vExample); writeln(GetEnumName(TypeInfo(TTypeKind),Ord(Value.Kind))); Writeln(value.AsType<variant>);
vExample := 1234; Value := TValue.From<variant>(vExample); writeln(GetEnumName(TypeInfo(TTypeKind),Ord(Value.Kind))); Writeln(value.AsType<variant>);
readln; end.
来源:https://www.cnblogs.com/lucken2000/p/17377847.html |