Home How to use TObjectList for arbitrary class type?
Reply: 2

How to use TObjectList for arbitrary class type?

Jerry Dodge
1#
Jerry Dodge Published in 2018-01-11 15:31:34Z

I'm still a bit fuzzy with generics in Delphi, but have been using TObjectList<> quite widely. Now I have a situation where I have a base class with such a private field, but needs to be created for an arbitrary class, also inherited from another base.

To clarify, I have two base classes:

type
  TItem = class;
  TItems = class;

  TItemClass = class of TItem;

  TItem = class(TPersistent)
  private
    FSomeStuffForAllIneritedClasses: TSomeStuff;
  end;

  TItems = class(TPersistent)
  private
    FItems: TObjectList<TItem>;
    FItemClass: TItemClass;
  public
    constructor Create(AItemClass: TItemClass);
    destructor Destroy; override;
    function Add: TItem;
    ...
  end;

This pair of classes is then further inherited into more specific classes. I'd like the object list to be shared for all of them, while each holds actually a different type internally.

type
  TSomeItem = class(TItem)
  private
    FSomeOtherStuff: TSomeOtherStuff;
    ...
  end;

  TSomeItems = class(TItems)
  public
    function Add: TSomeItem; //Calls inherited, similar to a TCollection
    procedure DoSomethingOnlyThisClassShouldDo;
    ...
  end;

Now the problem is when it comes to creating the actual object list. I'm trying to do it like this:

constructor TItems.Create(AItemClass: TItemClass);
begin
  inherited Create;
  FItemClass:= AItemClass;
  FItems:= TObjectList<AItemClass>.Create(True);
end;

However, the code insight complains about this:

Undeclared Identifier AItemClass

Even more, the compiler has yet a different complaint:

Undeclared Identifier TObjectList

Where, I do in fact have System.Generics.Collections used in this unit.

What am I doing wrong here, and how should I do this instead?

Stefan Glienke
2#
Stefan Glienke Reply to 2018-01-11 15:45:46Z

Make TItems generic:

TItems<T: TItem, constructor> = class(TPersistent)
private
  FItems: TObjectList<T>;
public
  constructor Create;
  destructor Destroy; override;
  function Add: T;
  ...
end;

constructor TItems.Create;
begin
  inherited Create;
  FItems:= TObjectList<T>.Create(True);
end;

function TItems<T>.Add: T;
begin
  Result := T.Create;
  FItems.Add(Result);
end;

If you inherit, simply put the correct generic parameter:

TSomeItems = class(TItems<TSomeItem>)
public
  procedure DoSomethingOnlyThisClassShouldDo;
  ...
end;
Jerry Dodge
3#
Jerry Dodge Reply to 2018-01-11 15:31:34Z

The TObjectList is not meant to be used in that manner. The fact that it was originally defined as TObjectList<TItem> means that it will expect you to create it this way as well. It needs to be defined with the precise class you intend to create it as.

Instead, just create it with TItem, and then whenever you create a new item which is supposed to be added to this list, then you create it using the class type. Any time you need to access the items in this list, just cast them on the fly.

For example...

Result:= FItemClass.Create;
FItems.Add(Result);

...can be the contents of your Add function.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.361019 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO