Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 libraries 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?

like image 292
Guest Avatar asked May 04 '11 20:05

Guest


2 Answers

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.

like image 77
Mason Wheeler Avatar answered Sep 23 '22 06:09

Mason Wheeler


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.

like image 21
Konrad Rudolph Avatar answered Sep 19 '22 06:09

Konrad Rudolph