How to use a generic method in a derived type

This would seem pretty simple and maybe I just missed a little syntax glue ... Here is my simple general example (Delphi XE3):

unit Unit1; interface uses generics.collections; type X = class public Id: Integer; end; XList<T : X> = class( TObjectList<T> ) function Find(Id: Integer) : T; end; Y = class(X) end; YList = class(XList<Y>) end; implementation { XList<T> } function XList<T>.Find(Id: Integer): T; var t: X; begin for t in Self do if t.Id = Id then Result := t; end; end. 

This will not compile with "[dcc32 Error] Unit1.pas (41): E2010 Incompatible types:" Y "and" X ". It is on the line:

 YList = class(XList<Y>) end; 

Y is obtained from X, so why is there a problem?

+7
generics inheritance delphi delphi-xe3
source share
2 answers

I had to override the Find method as follows to fix it:

 { XList<T> } function XList<T>.Find(Id: Integer): T; var item: T; begin for item in Self do if item.Id = Id then Exit(item); Result := nil; end; 

It is important here to replace the type used in the variable declaration from X to T

Then I simply renamed the variable from T to item to avoid a name clash with a placeholder of type T and moved Result := item to Exit(item) to return the item found and exit the method.

+6
source share

Answer Alex is the correct solution to the problem. And it is also good to return from a function as soon as the answer is known.

I would like to talk more about this answer. In particular, I would like to answer the question that you asked in the comments on Alex:

As an aside ... why not the original work? T is derived from X.

The problem code is here:

 function XList<T>.Find(Id: Integer): T; var t: X; begin for t in Self do if t.Id = Id then Result := t; end; 

A way to think about generics is to imagine what the code looks like when you instantiate a type and set a specific type parameter. In this case, replace T with Y Then the code looks like this:

 function XList_Y.Find(Id: Integer): Y; var t: X; begin for t in Self do if t.Id = Id then Result := t; end; 

Now you have a problem in the line that assigns Result :

 Result := t; 

Well, Result is of type Y , but T is of type X The relationship between X and Y is that Y derived from X So the instance of Y is X But instance X not Y And so the appointment is not valid.

As Alex pointed out correctly, you need to declare a loop variable of type T Personally, I would write the code as follows:

 function XList<T>.Find(Id: Integer): T; begin for Result in Self do if Result.Id = Id then exit; Result := nil; // or perhaps you wish to raise an exception if the item cannot be found end; 

This also applies to the problem that your search procedure does not return a return value if the item is not found. This issue you were compiling about would warn that you received the code before the actual compilation. I hope you turn on compiler warnings and work with them when they appear!

+8
source share

All Articles