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

gra*_*afd 6 delphi

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

list: TStringList;
obj: MyObject;

obj := MyObject.Create();
list.AddObject("real object", obj);
Run Code Online (Sandbox Code Playgroud)

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

list.AddObject("just an index", Pointer(7));
Run Code Online (Sandbox Code Playgroud)

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

for i := 0 to list.Count-1 do
  if list.Objects[i] is MyObject then
  begin
    // ...
    // Do something with list.Objects[i]
    // ...
  end;
Run Code Online (Sandbox Code Playgroud)

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

LU *_* RD 8

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

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

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.
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)

  • 在释放TStringList之前,不要忘记释放TVariantContainer对象(除非将其OwnsObjects属性设置为True-仅XE2 +),否则会泄漏内存。 (2认同)

Lie*_*ers 5

完全可以添加一个恰好指向一个对象的整数.同样,很可能有一个指向列表中已经释放了对象的对象的指针.

最重要的是,您可以随心所欲地在内存中查找,没有防弹方法来了解您的stringlist是否包含整数或指针.

因为你不应该混合不同的类型,也没有必要知道.更好的方法是创建两个包含 Stringlist的类,并使外部类类型安全地使用.那么你的问题就成了一个问题.

假设您的Delphi版本不支持泛型的示例

  TStringIntegerMap = class
    private FStringIntegerList: TStringList;
  public
    procedure Add(const Key: string; Value: Integer);
    ... // Add the other required equivalent TStringlist methods 
  end;

  TStringObjectMap = class
    private FStringObjectList: TStringList;
  public
    procedure Add(const Key: string; Value: TObject);
    ... // Add the other required equivalent TStringlist methods 
  end;
Run Code Online (Sandbox Code Playgroud)

请注意,这只是为了向您提供有关如何实现此类的要点.