开发者

Can I use generics to do the same operation on similar types of controls?

I am using Delphi 2010 and I have a unit where over the years I have added my own procedures and functions that can be used with any project I make, such as:

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

The above uses TListBox as a parameter, so whenever the above function is used I must supply a listbox that is of TListBox class.

Now suppose I have some other component librar开发者_开发问答ies that could work with the same function, For example the Jedi component classes.

How could I use the above function, when the Jedi listbox is TJvListBox class and my function is looking for TListBox class? Although both components are practically the same, the class names are different. If I provided the same function specifically for the TJvListBox it would likely work because they are both "listboxes":

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

Now, I have whole load of procedures and functions written in the same kind of way where I need to pass a component as a parameter. Having to rewrite them again just to work with a different component class is not feasible!

How can I write this with generics?


You can't write that with generics, unless your target classes all descend from the same base class of course. (But then you wouldn't need generics for it.)

If you really want something that can check if the ItemIndex property on any object <> -1, though, you can do that with a different Delphi 2010 feature: extended 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;

Careful, though. There's no compile-time type checking here, and this process is significantly slower than your original routine. You probably won't notice it, but if you call something like this in a tight loop, it will slow it down.


I don't understand how I can write this with Generics?

You can’t – not unless your component implements a common interface or inherits from a common base class with the standard ListBox, and that interface / base class offers the ItemIndex property.

In fact, this use-case isn’t such a great example of generics because using an interface or base class in the declaration would work just as well.


In this case, you can write two overloaded functions, one expecting TJvListBox and the other expecting TListBox.

In more complex cases this approach may not apply so well, but I think your case is simple enough for this solution.


I cannot look it up right now (on holiday, no Delphi), but don't TJvListBox and TListBox descend from a common ancestor (my guess would be: TCustomListBox)? In that case something like this should work:

interface

function TListBox_IsItemSelected(_ListBox: TCustomListBox): boolean;

implementation

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

Just in case ItemIndex (as I said: I cannot check right now) is protected in TCustomListBox, you can just use a typecast hack:

type
  TListBoxHack = class(TCustomListBox)
  end;

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

(I just thought I should mention this since the original question has already been answered: Using Generics does not help here.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜