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