我可以使用泛型对相似类型的控件执行相同的操作吗?

时间:2011-05-04 20:41:23

标签: delphi generics

我正在使用Delphi 2010,我有一个单元,多年来我添加了自己的程序和功能,可以用于我所做的任何项目,例如:

function ListBoxIsSelected(ListBox: TListBox): Boolean;
begin
  Result:= ListBox.ItemIndex <> -1;
end;

以上使用TListBox作为参数,因此无论何时使用上述函数,我都必须提供listbox类的TListBox

现在假设我有一些其他组件库可以使用相同的函数,例如Jedi组件类。

当Jedi listboxTJvListBox类并且我的函数正在寻找TListBox类时,我怎么能使用上面的函数?虽然两个组件实际上是相同的,但类名是不同的。如果我专门为TJvListBox提供了相同的功能,它可能会起作用,因为它们都是“列表框”:

function ListBoxIsSelected(ListBox: TJvListBox): Boolean;
begin
  Result:= ListBox.ItemIndex <> -1;
end;

现在,我需要将组件作为参数传递,以相同的方式编写完整的过程和函数。只是为了使用不同的组件类而不得不重写它们是不可行的!

我如何用泛型来写这个?

4 个答案:

答案 0 :(得分:9)

你不能用泛型来写,除非你的目标类当然都来自同一个基类。 (但那时你不需要泛型。)

如果你真的想要能够检查任何对象上的ItemIndex属性&lt;&gt;但是,您可以使用不同的Delphi 2010功能:扩展RTTI。

uses
  SysUtils, RTTI;

function IsSelected(item: TObject): boolean;
var
  context: TRttiContext;
  cls: TRttiType;
  prop: TRttiProperty;
  ItemIndex: integer;
begin
  if item = nil then
    raise Exception.Create('Item = nil');
  context := TRttiContext.Create;
  cls := context.GetType(item.ClassType);
  prop := cls.GetProperty('ItemIndex');
  if prop = nil then
    raise Exception.Create('Item does not contain an ItemIndex property.');
  ItemIndex := prop.GetValue(item).AsInteger;
  result := ItemIndex <> -1;
end;

但是要小心。这里没有编译时类型检查,这个过程明显慢于原始例程。你可能不会注意到它,但是如果你在紧密的循环中调用这样的东西,它会减慢速度。

答案 1 :(得分:2)

  

我不明白我怎么能用Generics写这个?

你不能 - 除非你的组件实现了一个公共接口,或者从一个带有标准ListBox的公共基类继承,并且该接口/基类提供了ItemIndex属性。

事实上,这个用例并不是泛型的一个很好的例子,因为在声明中使用接口或基类也可以正常工作。

答案 2 :(得分:0)

在这种情况下,您可以编写两个重载函数,一个期望TJvListBox,另一个期望TListBox。

在更复杂的情况下,这种方法可能不太适用,但我认为您的案例对于此解决方案来说足够简单。

答案 3 :(得分:0)

我现在无法查找(节假日,没有Delphi),但TJvListBox和TListBox不是从一个共同的祖先下降(我的猜测是:TCustomListBox)?在这种情况下,这样的事情应该有效:

interface

function TListBox_IsItemSelected(_ListBox: TCustomListBox): boolean;

implementation

function TListBox_IsItemSelected(_ListBox: TCustomListBox): boolean;
begin
  Result := _ListBox.ItemIndex <> -1;
end;

以防万一ItemIndex(正如我所说:我现在无法检查)在TCustomListBox中受到保护,你只能使用一个类型攻击:

type
  TListBoxHack = class(TCustomListBox)
  end;

function TListBox_IsItemSelected(_ListBox: TCustomListBox): boolean;
begin
  Result := TListBoxHack(_ListBox).ItemIndex <> -1;
end;

(我以为我应该提一下,因为原来的问题已经回答了:使用Generics在这里没有帮助。)