#1 2015-05-17 20:22:37

dexter
Member
Registered: 2015-04-24
Posts: 53

TDocVariantData.Value vs TDocVariantData.Values

Hi,

here is the code sample.

var
  V, V2                                 : TDocVariantData;
begin
  V.InitJSON('{"DATA":[{"NAME":"Name1","COMMENT":"Comment1"},{"NAME":"Name2","COMMENT":"Comment2"}],"DATA_ROWS":2}');
  V2 := TDocVariantData(V.Values[0]);
  Assert(V2.Kind = dvArray); // <-- here is OK
  V2 := TDocVariantData(V.Value[0]);
  Assert(V2.Kind = dvArray); // <- here is exception
end;

When I'm accessing Values property - it returns data as array.
When I'm accessing Value property by index or name - data kind is dvUndefined.

Is this proper behavior?

Offline

#2 2015-05-18 07:00:06

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,272
Website

Re: TDocVariantData.Value vs TDocVariantData.Values

Are you sure V.Value[0] is a TDocVariantData?
I guess not, it is a variant with varByRef or varVariant type.
So writing TDocVariantData(V.Value[0]) is unsafe.

If you are not 100% sur that a variant is a TDocVariantData, first check the exact variant type by using DocVariantType.IsOfType(V.Value[0]).

See http://synopse.info/files/html/Synopse% … l#TITLE_37

But you must ensure that the variant instance is really a TDocVariant kind of data before transtyping e.g. by calling DocVariantType.IsOfType(aVariant) or the DocVariantData(aVariant)^ or DocVariantDataSafe(aVariant)^ functions, which both will work even for members returned as varByRef via late binding (e.g. V2.doc):

if DocVariantType.IsOfType(V1) then
with TDocVariantData(V1) do             // direct transtyping
   for i := 0 to Count-1 do              // direct access to the Count: integer field
     writeln(Names[ i ],'=',Values[ i ]);    // direct access to the internal storage arrays

writeln(V2.doc); // will write  '{"name":"john","doc":{"one":1,"two":2.5}}'
if DocVariantType.IsOfType(V2.Doc) then // will be false, since V2.Doc is a varByRef variant
   writeln('never run');                 // .. so TDocVariantData(V2.doc) will fail
with DocVariantData(V2.Doc)^ do         // note ^ to de-reference into TDocVariantData
   for i := 0 to Count-1 do              // direct access the TDocVariantData methods
     writeln(Names[ i] ,'=',Values[ i ]);
  // will write to the console:
  //  one=1
  //  two=2.5

In practice, DocVariantDataSafe(aVariant)^ may be preferred, since DocVariantData(aVariant)^ would raise an EDocVariant exception if aVariant is not a TDocVariant, but DocVariantDataSafe(aVariant)^ would return a "fake" void DocVariant instance, in which Count=0 and Kind=dbUndefined.

In all case, there is NO benefit of using V.Value[0].
If you access at the TDocVariantData level, you should better use directly V.Values[0].

Offline

#3 2015-05-18 12:17:16

dexter
Member
Registered: 2015-04-24
Posts: 53

Re: TDocVariantData.Value vs TDocVariantData.Values

Hi,

thanks for answer.

Actually I was trying initially to access by Name, i.e. V2 := TDocVariantData(V.Value['DATA']).

If V2 := TDocVariantData(V.Values[0]) keeps the Kind = dvArray, why V.Value['DATA'] does not?

Isn't V.Value at the end taking from the same V.Values?

Offline

#4 2015-05-18 12:47:57

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,272
Website

Re: TDocVariantData.Value vs TDocVariantData.Values

No, V.Value[] returns the value by reference, for obvious performance reasons.
Please read again my answer: this is a variant of type varByRef or varVariant, not directly a TDocVariantData.

So you would need to use DocVariantData() or DocVariantDataSafe() to access it.

Offline

#5 2015-05-18 13:03:37

dexter
Member
Registered: 2015-04-24
Posts: 53

Re: TDocVariantData.Value vs TDocVariantData.Values

Got it now, thanks.

Offline

Board footer

Powered by FluxBB