views:

205

answers:

4

I have a generic list class:

TMyObjectlist<T: TMyObject> = class(TObjectList<T>);

and a derived list class:

TMyDerivedObjectList = class(TMyObjectList<TMyDerivedObject>);

I want to check if an instance MyList of TMyDerivedObjectList inherits from TMyObjectList, however:

MyList.InheritsFrom(TMyObjectlist<TMyObject>)

returns False.

It turns out that MyList.Classparent is of type TMyObjectList<TMyDerivedObject>.

Does anybody knows how to check the InheritsFrom in this case?

A: 

TObjectList<t> does not exist in compiled code on the instance that was create when you specified the type exists.

So you can't check if it is derived from a non concrete class.

Robert Love
TobjectList<TButton>.InheritsFrom(TList<TButton>) returns True, so you can check if class is derived from generic (non concrete) class.
Cosmin Prund
TList<TButton> is concrete. TList<T> is not.
Robert Love
+1  A: 

This is because your list doesn't inherit from a similar list whose generic type inherits from the base class. They're not substitutable for each other in the same way that the generic types are. In fact, they can't be, not without ruining the type safety that a lot of things in the language depend on.

To understand why, imagine passing MyList to a routine that expects a TMyObjectlist<TMyObject>. Everything's fine, right up until the routine calls .Add and sticks a TMyIncompatibleObject, which also descends from TMyObject, into the list. Then you've broken type safety.

There are ways around this problem, but they haven't been implemented in Delphi yet. Hopefully the Delphi team will get around to it soon, because that would make Generics a lot more useful.

Mason Wheeler
+4  A: 

Just draw up the inheritance scheme for both list objects and you'll clearly see why the InheritsFrom doesn't work. In Generics.Collections we have:

TEnumerable<T> = class abstract;
TList<T> = class(TEnumerable<T>);
TObjectList<T> = class(TList<T>);

In your example we have:

TMyObject = class;
TMyDerivedObject = class(TMyObject);

So we get those two inheritance trees:

TObject
|
TEnumerable<TMyDerivedObject>
|
TList<TMyDerivedObject>
|
TObjectList<TMyDerivedObject>

and then we have:

TObject
|
TEnumerable<TMyObject>
|
TList<TMyObject>
|
TObjectList<TMyObject>

As you can see, the only common ancestor for both list types is TObject!

Cosmin Prund
A: 

In Delphi, constructed types are not covariant with their type parameters. Given T, U, V and U <= V, then T<U> is not <= T<V>.

See Covariance and contravariance.

nang