无效的变体类型错误Delphi 2010

时间:2010-12-05 23:03:44

标签: delphi generics delphi-2010 variant

// 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;

在iccDynamicObject.define()中设置DELPHI 2010中的断点 - > tmp:= locate(_id); 将导致@ Project Project1.exe引发异常类EVariantBadVarTypeError,并显示消息“Invalid variant type”。 @

Code在DELPHI 7中测试过,没遇到过这个问题!

PS。代码是用delphi-7样式重写的,没有用于演示问题的类内类型......

已解决 - >不要使用类内通用类型,例如

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;

这样的事情会让调试器或编译器做出意想不到的事情! 代码编译并正常工作。但就我而言,单位增长代码变得不稳定 并强迫我做一些代码重构,只是一点点,但不仅仅是不方便......

你被注意到:)))

4 个答案:

答案 0 :(得分:5)

这是D2010中的一个已知错误,已经reported in QualityCentral并已在XE中修复。

答案 1 :(得分:1)

尝试在您为结果指定nil的位置旁边的locate方法中指定tmp := nil;。如果这解决了异常,我将解释原因。

答案 2 :(得分:1)

此问题是由意外的调试器或编译器行为引起的,并且此类行为是由Delphi 2010中的错误引起的(它们可能在Delphi XE中修复,如David Heffernan所述)。

我只有一个结论:不要使用类内通用类型,例如:

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;

这样的事情会导致调试器或编译器做出意想不到的事情。代码编译并正常工作。但就我而言,随着单位增长代码变得不稳定,它迫使我做了一些代码重构。

答案 3 :(得分:0)

您是否尝试使用新的VCL表单应用程序,包括您提供的代码?
我做了......

1-设置断点不会做任何事情(也没有伤害),因为你必须阅读你的项目来调用get(_id)
2-我为此添加了一行:

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

3-断点按预期工作,没有任何异常

所以我猜测还有其他事情发生了......