Tuesday, September 22, 2009

TValue in Depth

TValue is one of the key Types in the new RTTI System. We already covered some of the basics in the introduction to TValue. It's now time to pull back the covers and explorer how it was designed so you can exploit the entire power of TValue.

Before we get too far, lets take a look at the field in the interface of TValue.

TValue = record ... private FData: TValueData; end;

Since TValue can store data from any type. I was interested in how this accomplished, it proved usefulin determining how to store data from various unknown types I knew I would be throwing at it in the future.

begin Ctx := TRttiContext.Create; // Create empty record structure TValue.Make(nil,TypeInfo(TRect),RecValue); // Set the Left and Right Members, using the pointer to the Record Ctx.GetType(TypeInfo(TRect)).GetField('Left').SetValue(RecValue.GetReferenceToRawData,10); Ctx.GetType(TypeInfo(TRect)).GetField('Right').SetValue(RecValue.GetReferenceToRawData,20); // Extract the record to report the results. RecValue.ExtractRawData(@RecData); Writeln(RecData.Left); Writeln(RecData.Right); readln; Ctx.Free;end.

Output:

1020

These little examples show how to deal with types that you don't know about at compile time. However, sometimes you do know the type you will be working with at compile time. When this is know it becomes much easier to to work with using a the Generic/Parametrized Type functions that TValue Provides:

I thought it meant that I would be taking a Variant and stuffing it into the TValue, however you will find that it really is not doing that, it's storing the data using originating type, the following code shows how it behaves.

There are also other ways to work with TValue that I just don't have the time to cover. I recommend opening up Rtti.pas and exploring the interface to see everything that is available. The items I failed to cover are fairly straight forward.

I use TValue.Make(nil,TypeInfoVar,OutputTValue); a lot on dynamic arrays. In Delphi xe2 the result OutputTvalue.isEmpty=false. I recently tried Delphi 10 Berlin. Here the resulting value is OutputTvalue.isEmpty=true. So I had to change my tests fromif OutputValue.isEmpty then doErrorif not OutputValue.isArray then doError