delphi – 如何区分TStringList中的Pointer和TObject条目?

我们可以将字符串和一些关联的对象添加到TStringList:
list: TStringList;
obj: MyObject;

obj := MyObject.Create();
list.AddObject("real object",obj);

另外,简单地将字符串与指针连接起来非常方便,即整数值,如下所示:

list.AddObject("just an index",Pointer(7));

如果我以后访问此列表中的对象,如何知道它是MyObject还是仅仅是指针?我想要这样的东西:

for i := 0 to list.Count-1 do
  if list.Objects[i] is MyObject then
  begin
    // ...
    // Do something with list.Objects[i]
    // ...
  end;

但是如果list.Objects [i]只是一个指针,这显然会导致访问冲突.
提前致谢!

解决方法

如果要将整数和对象安全地存储到一个字符串列表中,请定义一个变量容器类来保存整数或对象.

下面是这样一个粗略概述的类,包括一个测试项目.

unit VariantContainer;

interface

uses Variants,SysUtils;

Type
  TVariantContainer = class
    private
      FVariant : Variant;
    public
      constructor Create(aValue: Integer); overload;
      constructor Create(aValue: TObject); overload;
      function IsInteger: Boolean;
      function IsObject: Boolean;
      function AsObject: TObject;
      function AsInteger: Integer;
  end;

implementation

function TVariantContainer.AsInteger: Integer;
begin
  if not IsInteger then
    raise Exception.Create('Variant is not Integer');
  Result := FVariant;    
end;

function TVariantContainer.AsObject: TObject;
begin
  if not IsObject then
    raise Exception.Create('Variant is not TObject');
  Result := TVarData(FVariant).VPointer;
end;

function TVariantContainer.IsInteger: Boolean;
begin
  Result := VarIsType( FVariant,varInteger);
end;

function TVariantContainer.IsObject: Boolean;
begin
  Result := VarIsType(FVariant,varByRef);
end;

constructor TVariantContainer.Create(aValue: Integer);
begin
  Inherited Create;
  FVariant := aValue;
end;

constructor TVariantContainer.Create(aValue: TObject);
begin
  Inherited Create;
  TVarData(FVariant).VType:= VarByRef;
  TVarData(FVariant).VPointer:= aValue;
end;

end.
program ProjectTestVariantContainer;

{$APPTYPE CONSOLE}
uses
  Variants,SysUtils,Classes,VariantContainer;

Type
  TMyObj = class
    s:String;
  end;

var
  sList: TStringList;
  o: TMyObj;
  i: Integer;
begin
  o := TMyObj.Create;
  o.s := 'Hello';
  sList := TStringList.Create;
  sList.OwnsObjects := True;  // List owns container objects
  sList.AddObject('AnInteger',TVariantContainer.Create(3));
  sList.AddObject('AnObject',TVariantContainer.Create(o));
  for i := 0 to sList.Count-1 do
  begin
    if Assigned(sList.Objects[i]) then 
    begin
      if TVariantContainer(sList.Objects[i]).IsInteger then
        WriteLn( TVariantContainer(sList.Objects[i]).AsInteger)
      else
      if TVariantContainer(sList.Objects[i]).IsObject then
        WriteLn( TMyObj(TVariantContainer(sList.Objects[i]).AsObject).s);
    end;
  end;
  ReadLn;
  o.Free;
  sList.Free;  
end.

相关文章

ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:...
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂...
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (By...