Focker
Focker

Reputation: 215

Invalid variant type error Delphi 2010

// interface

    iccItem =
        class
            ID   : String;
            DATA : Variant;
            constructor Create( _id : String; _data : Variant);
        end;

    iccDynamicObject =
        class
             private
                 FItems : TList;
                 function locate( _id : String) : iccItem;
             public
                 constructor Create();
                 destructor Destroy(); override;
             public
                 procedure define( _id : String; _dta : Variant);
                 //function get( _ndx : DWORD)  : Variant; overload;// link to original data
                 function get( _id  : String) : Variant; overload;
             public
                 property Items[_id : String] : Variant read get write define; default;
        end;


// implementation

{ iccDynamicObject }

constructor iccItem.Create( _id : String; _data : Variant);
begin
    ID   := _id;
    DATA := _data;
end;

function iccDynamicObject.locate( _id : String) : iccItem;
var ndx : integer;
    tmp : iccItem;
begin
    result := nil;

    for ndx := 0 to FItems.Count - 1 do
        begin
            tmp := iccItem( FItems[ndx]);
            if tmp.ID = _id
                then begin
                         result := tmp;
                         exit;
                     end;
        end;
end;

constructor iccDynamicObject.Create();
begin
    FItems := TList.Create();
end;

destructor iccDynamicObject.Destroy();
begin
    {$MESSAGE 'clear here'}

    FItems.Destroy();
    inherited;
end;

procedure iccDynamicObject.define( _id : String; _dta : Variant);
var tmp : iccItem;
begin
    tmp := locate( _id);
    if tmp = nil
        then FItems.Add( iccItem.Create( _id, _dta) )
        else tmp.DATA := _dta;
end;

//function iccDynamicObject.get( _ndx : DWORD) : Variant;
//begin
//    result.vPointer := nil;
//end;

function iccDynamicObject.get( _id : String) : Variant;
var tmp : iccItem;
begin
    tmp := locate( _id);
    if tmp = nil
        then result.vaNull := true
        else result := locate( _id).DATA;
end;


// using
procedure TForm1.FormCreate(Sender: TObject);
var c : iccDynamicObject;
begin
    c := iccDynamicObject.Create;

    c['asd'] := 123;

    c.Destroy;
end;

Set breakpoint in DELPHI 2010 at iccDynamicObject.define() -> tmp := locate( _id); will cause @Project Project1.exe raised exception class EVariantBadVarTypeError with message 'Invalid variant type'.@

Code was tested in DELPHI 7, and this problem was not encountered!

ps. code was rewritten in delphi-7 style without in-class types for demonstrating a problem...

SOLVED -> Do not use in-class generic types, such as

classDef<_type> = 
    class
        type
            // this
            internalClass<_anotherType> =
                class
                    private
                        FSomething : _anotherType;
                end;
            // or this one
            internalClass2 =
                class
                    private
                        FSomething : _type;
                end;
        private
            FInternalClass  : internalClass<_type>;
            FInternalClass2 : internalClass;
    end;

Such things will procure debugger or compiler to do UNEXCECTED THINGS!!! Code compiles and work correctly. But in my case, with Unit growth code become unstable and coerce me to make some code-refactoring, just a little, but more than inconvenient...

You are Noticed :)))

Upvotes: 0

Views: 4339

Answers (4)

Focker
Focker

Reputation: 215

This problem occured by unexpected debugger or compiler behavior, and such behavior was caused by bugs in Delphi 2010 (they might be fixed in Delphi XE, as David Heffernan mentioned).

I have only one conclusion: Do not use in-class generic types, such as:

classDef<_type> = 
    class
        type
            // this
            internalClass<_anotherType> =
                class
                    private
                        FSomething : _anotherType;
                end;
            // or this one
            internalClass2 =
                class
                    private
                        FSomething : _type;
                end;
        private
            FInternalClass  : internalClass<_type>;
            FInternalClass2 : internalClass;
    end;

Such things will cause the debugger or compiler to do unexpected things. The code compiles and works correctly. But in my case, with Unit growth code becoming unstable it has forced me to do some code-refactoring.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 612954

This is a known bug in D2010 which has been reported in QualityCentral and fixed in XE.

Upvotes: 5

Francesca
Francesca

Reputation: 21640

Did you try with a New VCL Forms Applications, including the code you provided?
I did...

1- setting the break point does not do anything (no harm either), because you have to read your item to call get(_id)
2- I added a line to that effect:

c['asd'] := 123;
i := c['asd'];   // <=== added
c.Destroy;

3- the breakpoint worked as expected, without any exception

So I'm guessing there is something else going on....

Upvotes: 0

dthorpe
dthorpe

Reputation: 36082

Try assigning tmp := nil; in the locate method next to where you assign nil to result. If this resolves the exception, I'll explain why.

Upvotes: 1

Related Questions