如何在Delphi中调用TObjectDictionary的继承构造函数

如何在Delphi中调用TObjectDictionary的继承构造函数,delphi,generics,constructor,inherited,Delphi,Generics,Constructor,Inherited,在阅读了TDictionary相对于TStringList的显著性能改进后,我创建了以下课程: TAnsiStringList = class(TObjectDictionary<AnsiString,TObject>) public constructor Create(const OwnsObjects: Boolean = True); reintroduce; destructor Destroy; override; pr

在阅读了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;
…希望调用此TObjectDictionary构造函数:

    constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer = 0); overload;
    constructor Create(ACapacity: Integer = 0); overload;
…如果指定了Ownerships参数。如果未指定Ownerships参数,我希望调用以下继承的TDictionary构造函数:

    constructor Create(Ownerships: TDictionaryOwnerships; ACapacity: Integer = 0); overload;
    constructor Create(ACapacity: Integer = 0); overload;
代码编译并运行,但是当我调用

    inherited Create([doOwnsKeys,doOwnsValues]) I get the following error:
无效的类类型转换

有人知道我做错了什么吗?有没有合适的方法


TIA

问题在于,当物品被移除时,您要求容器免费呼叫您的钥匙。但是您的密钥不是类,因此这是一个无效的请求。这是在运行时而不是编译时捕获的,因为直到运行时才确定所有权

您只需要doownsvalue,应该删除doownskey

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

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

如果您一心想创建一个子类,那么我会这样做:

  { TAnsiStringList }

    constructor TAnsiStringList.Create(const OwnsObjects: Boolean = True);
    begin
      if OwnsObjects then
        inherited Create([doOwnsKeys,doOwnsValues])
      else
        inherited Create;
    end;
type
  TAnsiStringDict<T: class> = class(TObjectDictionary<AnsiString, T>)
var
  ListBoxDict: TAnsiStringDict<TListBox>;
这将允许类的使用者决定将哪种类型的对象放入字典中,并维护编译时类型安全

因此,当您想要一个列表框字典时,您可以声明一个如下所示的变量:

  { TAnsiStringList }

    constructor TAnsiStringList.Create(const OwnsObjects: Boolean = True);
    begin
      if OwnsObjects then
        inherited Create([doOwnsKeys,doOwnsValues])
      else
        inherited Create;
    end;
type
  TAnsiStringDict<T: class> = class(TObjectDictionary<AnsiString, T>)
var
  ListBoxDict: TAnsiStringDict<TListBox>;

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

您只需要doownsvalue,应该删除doownskey

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

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

如果您一心想创建一个子类,那么我会这样做:

  { TAnsiStringList }

    constructor TAnsiStringList.Create(const OwnsObjects: Boolean = True);
    begin
      if OwnsObjects then
        inherited Create([doOwnsKeys,doOwnsValues])
      else
        inherited Create;
    end;
type
  TAnsiStringDict<T: class> = class(TObjectDictionary<AnsiString, T>)
var
  ListBoxDict: TAnsiStringDict<TListBox>;
这将允许类的使用者决定将哪种类型的对象放入字典中,并维护编译时类型安全

因此,当您想要一个列表框字典时,您可以声明一个如下所示的变量:

  { TAnsiStringList }

    constructor TAnsiStringList.Create(const OwnsObjects: Boolean = True);
    begin
      if OwnsObjects then
        inherited Create([doOwnsKeys,doOwnsValues])
      else
        inherited Create;
    end;
type
  TAnsiStringDict<T: class> = class(TObjectDictionary<AnsiString, T>)
var
  ListBoxDict: TAnsiStringDict<TListBox>;

谢谢你的及时回复。我采用这种方法的原因很简单,因为在大型列表上执行查找时,性能有所提高。我经常使用stringlist作为对象列表上基于文本的索引系统。如果我不需要使用数字索引查找字符串或对象,为什么使用TObjectDictionary不是更好的方法,因为它的查找速度快得多?您可以直接使用TObjectDictionary。如果您想要一个明确强制您选择所有权的版本,并为键选择AnsiString,那么至少让值类型保持参数化。然后你就可以有类型安全了。您可能会发现使用Anistring时性能更差。除非您在其他任何地方使用AnsiString,并且不要接触将转换为UTF-16或从UTF-16转换而来的RTL/VCL方法。如果我不需要使用数字索引查找字符串或对象,那就好了。这是我的最后一段。但是你的类名错了。每个读取TAnsiStringList的Delphi编码器都会假设一个有序的数组,比如容器。顺便说一句,我把一个小的测试应用程序放在一起测试性能差异,我发现向TDictionary添加项目比TStringList慢30-50%。但在TDictionary上查找要快得多,因此可以抵消性能损失。我之所以这样创建这个类,是因为我们的遗留软件使用了一个类似的类,它不需要索引排序,并且使用了旧的.indexOfstring>-1方法,这是由TDictionary的.ContainsKeystring函数非常有效地处理的。我完全可以权衡性能。如果将“排序”设置为True,则字符串列表查找将大大改进。因为
然后可以使用二进制搜索。我想我在答案的第一部分回答了这个问题。其余的都是一般性的建议。1.我认为这个班的名字不对。2.我认为您可以按原样使用TObjectDictionary,而无需子类化。3.如果您使用子类,请将value参数保留为打开状态,以便使用者指定。感谢您的及时回复。我采用这种方法的原因很简单,因为在大型列表上执行查找时,性能有所提高。我经常使用stringlist作为对象列表上基于文本的索引系统。如果我不需要使用数字索引查找字符串或对象,为什么使用TObjectDictionary不是更好的方法,因为它的查找速度快得多?您可以直接使用TObjectDictionary。如果您想要一个明确强制您选择所有权的版本,并为键选择AnsiString,那么至少让值类型保持参数化。然后你就可以有类型安全了。您可能会发现使用Anistring时性能更差。除非您在其他任何地方使用AnsiString,并且不要接触将转换为UTF-16或从UTF-16转换而来的RTL/VCL方法。如果我不需要使用数字索引查找字符串或对象,那就好了。这是我的最后一段。但是你的类名错了。每个读取TAnsiStringList的Delphi编码器都会假设一个有序的数组,比如容器。顺便说一句,我把一个小的测试应用程序放在一起测试性能差异,我发现向TDictionary添加项目比TStringList慢30-50%。但在TDictionary上查找要快得多,因此可以抵消性能损失。我之所以这样创建这个类,是因为我们的遗留软件使用了一个类似的类,它不需要索引排序,并且使用了旧的.indexOfstring>-1方法,这是由TDictionary的.ContainsKeystring函数非常有效地处理的。我完全可以权衡性能。如果将“排序”设置为True,则字符串列表查找将大大改进。因为它可以使用二进制搜索。我想我在答案的第一部分回答了这个问题。其余的都是一般性的建议。1.我认为这个班的名字不对。2.我认为您可以按原样使用TObjectDictionary,而无需子类化。3.如果您使用子类,请将value参数保留为打开状态,以便使用者指定。