1

在阅读了 TDictionary 相对于 TStringList 的显着性能改进后,我创建了以下类:

    TAnsiStringList = class(TObjectDictionary<AnsiString,TObject>)
    public
      constructor Create(const OwnsObjects: Boolean = True); reintroduce;
      destructor Destroy; override;
      procedure Add(const AString: AnsiString);
      procedure AddObject(const AString: AnsiString; AObject: TObject);
    end;

我这样编写构造函数:

  { TAnsiStringList }

    constructor TAnsiStringList.Create(const OwnsObjects: Boolean = True);
    begin
      if OwnsObjects then
        inherited Create([doOwnsKeys,doOwnsValues])
      else
        inherited Create;
    end;

...期望这个 TObjectDictionary 构造函数将被调用:

    constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer = 0); overload;

...如果指定了 Ownerships 参数。如果没有指定 Ownerships 参数,我预计会调用以下继承的 TDictionary 构造函数:

    constructor Create(ACapacity: Integer = 0); overload;

代码编译并运行,但是当我调用

    inherited Create([doOwnsKeys,doOwnsValues]) I get the following error:

无效的类类型转换

有谁看到我做错了什么,有没有合适的方法来做到这一点?

TIA

4

1 回答 1

5

问题是您要求容器Free在移除项目时调用您的键。但是您的密钥不是类,因此这是一个无效的请求。这是在运行时而不是编译时捕获的,因为直到运行时才确定所有权。

您只想要doOwnsValues并且应该删除doOwnsKeys.

 if OwnsObjects then
    inherited Create([doOwnsValues])
 else
   inherited Create;

对于它的价值,如果你试图制作一个AnsiString等价于TStringList,那么你的方法是有缺陷的。字符串列表是有序容器,但字典不是。您将无法按整数索引、按顺序迭代等等。我也不明白为什么要强制此类的所有使用者将对象声明为 type TObject。您应该将该参数留给消费者指定。这就是泛型的美妙之处。

也许你不想要一个有序的容器,在这种情况下你需要一本字典。但在这种情况下,您根本不需要创建新类。您可以TObjectDictionary按原样使用。

如果您对创建子类一无所知,那么我会这样做:

type
  TAnsiStringDict<T: class> = class(TObjectDictionary<AnsiString, T>)

这将允许类的使用者决定他们将哪种类型的对象放入字典中,并保持编译时类型安全。

所以,当你想要一个列表框的字典时,你可以声明一个像这样的变量:

var
  ListBoxDict: TAnsiStringDict<TListBox>;
于 2013-04-12T14:28:44.467 回答