Thinking about a generic class

type
  TMyClass<T> = class
  end;

If we would like to dynamically generate new instances of the type T (and possibly return it), what would you think of?

The official way

There is a built-in way to do it by declaring T as both type class and a constructor:

type
  TMyClass<T: class, constructor> = class
  end;

By doing this way, we will be able to initiate a new instance by simply calling T.Create without knowing what class the T is. But wait, there are classes that must be constructed with its own create method instead of the default TObject.Create, like TForm, TThread and any classes with custom parametered constructor.

Failed attempts

First, I came up with a new class like this:

type
  TMyClass<T: TForm> = class
  end;

And attempted to instantiate with My := TMyClass<TForm1>.
But the compiler didn't allow me to call T.Create(nil) because the compiler doesn't understand that the TForm is a class and has a Create method.

Then I tried to do a typecast like this:

 My := TForm1(T).Create;

However, the compiler complained that TForm1 is incompatible with TForm. WTF?!
Later, I realized that this is to prevent from accidentally return an ancestor class as a child class, e.g.

  TMyClass<T: TForm> = class
   function init(): T;
  end;

  function TMyClass<T>.init(): T;
  var
   subclass: T;
  begin
    subclass:= T.Create(nil); // <-- error: Create is undefined
    subclass:= TForm(T).Create(nil); // <-- error: TForm1 is not compatible with TForm
  end;

var
  v1: TMyClass<TForm1>; 

The second subclass creator actually created a TForm base class and returned it as its super class TForm1 which is certainly not allowed.

The RTTI way

With RTTI, we are able to locate the Create method, and invoke it with any parameters we want

function TMyClass<T>.NewInstance(): T;
var
  p: TRttiParameter;
  ctx: TRttiContext;
  rtype: TRttiType;
  method: TRttiMethod;
  params: TArray<TRttiParameter>;
  I: Integer;
  realParams: TArray<TValue>;
begin
  rtype:= ctx.GetType(TypeInfo(T));
  method:= rtype.GetMethod('Create'); // Find the Create method
  params := method.GetParameters; // get parameters info
  SetLength(realParams, Length(params));
  for I := 0 to Length(params) - 1 do
    case params[I].ParamType.TypeKind of // do whatever you need to initialize parameters
      tkClass:
        realParams[I] := TValue.From<TObject>(nil);
      tkString:
        realParams[I] := TValue.From<string>('');
      tkUString:
        realParams[I] := TValue.From<UnicodeString>('');
      tkInteger, tkInt64:
        realParams[I] := TValue.From<Integer>(0);
    end;
  result := method.Invoke(rtype.AsInstance.MetaclassType, params ).AsType<T>; // call the constructor
end;

Voila!

References: