delphigenerics

Generic to convert list of interfaces in delphi


I have to convert different interface lists to TList<IInterface>.

TList<IOtherInterface> as TList<IInterface>

doesn't work so I've tried this generic:

interface

type
    TInterfaceList = class(TList<IInterface>)
    end;

    TInterfaceListConverter<T:IEnumerable<IInterface>; I:IInterface> = class
        public
            function Convert(_from: T): TInterfaceList;
    end;

implementation

function TInterfaceListConverter<T, I>.Convert(_from: T): TInterfaceList;
begin
    Result := TInterfaceList.Create();
    for var i : I in _from do begin
        Result.Add(i as IInterface);
    end;
end;

but it won't compile. I get E2010: Inkompatible types: 'I' and 'TObject'. Is there a way to do this with a generic?


Solution

  • The possibility to cast a generic type x<derived> to x<base> is called covariance (I blogged about this a while ago - especially in the context of collections - see Generics and variance).

    The short story: Delphi does not support this, and you have to use a hard cast while being very careful.

    When performing any reading access on your TList<IOtherInterface> being hard cast to TList<IInterface>, that is fine - however, you must not add any interface to it which is not an IOtherInterface, which would be possible because due to the hard cast you are now dealing with a TList<IInterface>.

    If you do that locally inside of one routine, you should write some comment to remind you or someone else about this. If you don't need index access, you can also consider hardcasting it to TEnumerable<IInterface> because that only allows read access and thus would qualify as covariant in languages that support variance.