Domanda

Data una stringa di testo che contiene un nome di tipo, c'è qualche modo per ottenere il tipo appropriato per sé?

che sto cercando di fare qualcosa di simile:

type
  TSomeType<T> = class
    // yadda yadda
  end;

procedure DoSomething;
var
  obj : TObject;
begin
  o := TSomeType<GetTypeByName('integer')>.Create;
  // do stuff with obj
end;

Ho guardato diverse spiegazioni RTTI in linea e guardato attraverso le unità di Delphi e non vedo quello che sto cercando. È possibile?

È stato utile?

Soluzione

No, i generici sono del tutto compiletime.

Altri suggerimenti

La nuova unità RTTI in Delphi 2010 ha un modo di recuperare i tipi dichiarati nella sezione di interfaccia di unità. Per ogni dato tipo, rappresentato da un'istanza TRttiType, la proprietà TRttiType.QualifiedName restituisce un nome che può essere utilizzato con TRttiContext.FindType tardi per recuperare il tipo. Il nome completo è il nome dell'unità completo (incluso namespace, se esistono), seguito da un '', seguita dal nome di tipo completo (inclusi i tipi esterni se nested).

Quindi, si potrebbe recuperare una rappresentazione del tipo Integer (sotto forma di un TRttiType) con context.FindType('System.Integer').

Ma questo meccanismo non può essere utilizzato per recuperare istanze di tipi generici che non sono stati istanziati in fase di compilazione; istanziazione in fase di esecuzione richiede la generazione di codice runtime.

Si può sempre registrare i tipi in una sorta di registro (gestito da un elenco di stringhe o un dizionario) e creare una funzione di fabbrica per poi tornare l'oggetto appropriato. Purtroppo si dovrebbe sapere in anticipo quali tipi che stavano per bisogno. Qualcosa di simile alle funzioni di Delphi RegisterClass e FindClass (nell'unità di classi). Il mio pensiero è quello di mettere il tipo di modello generico nella lista direttamente.

Un esempio di possibile utilizzo:

RegisterCustomType('Integer',TSomeType<Integer>);
RegisterCustomType('String',TSomeType<String>);

if FindCustomType('Integer') <> nil then
  O := FindCustomType('Integer').Create;

Modifica Ecco una semplice implementazione specifica utilizzando un tDictionary da Generics.Collections per gestire la memorizzazione registro ... Lascio l'estrazione di questo in metodi utili come un semplice esercizio per il lettore.

var
  o : TObject;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) then
    ShowMessage(o.ClassName);
end;

Un altro EDIT: stavo dando qualche pensiero questo la scorsa notte, e ha scoperto un'altra tecnica che è possibile unire in questo concetto. Interfacce. Ecco un esempio veloce non fare nulla, ma può essere facilmente esteso:

TYPE
  ITest = interface
    ['{0DD03794-6713-47A0-BBE5-58F4719F494E}']
  end;

  TIntfList<t> = class(TList<T>,ITest)
  public
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

procedure TForm1.Button7Click(Sender: TObject);
var
  o : TObject;
  fTestIntf : ITest;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TIntfList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) and Supports(o,ITest,fTestIntf) then
    ShowMessage(o.ClassName);
end;

Naturalmente si dovrà implementare i metodi QueryInterface, _AddRef e _Release ed estendere l'interfaccia di fare qualcosa di più utile.

Se si dimentica generici e tipi di base, la funzione "RegisterClass" sarebbe utile. Ma non funziona per i medicinali generici o tipi di base.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top