Pergunta

Dada uma seqüência de texto contendo um nome de tipo, há alguma maneira de obter o próprio tipo apropriado?

Eu estou olhando para fazer algo como isto:

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

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

Eu olhei várias explicações RTTI em linha e olhou através das unidades de Delphi e não vê o que eu estou procurando. Isso é possível?

Foi útil?

Solução

Não, os genéricos são inteiramente compiletime.

Outras dicas

A nova unidade RTTI no Delphi 2010 tem uma maneira de recuperar tipos declarados na seção interface de unidades. Para qualquer tipo de dado, representado por uma instância TRttiType, a propriedade TRttiType.QualifiedName retorna um nome que pode ser usado com TRttiContext.FindType mais tarde para recuperar o tipo. O nome qualificado é o nome da unidade completa (incluindo espaços de nomes, se elas existirem), seguido por uma '', seguido pelo nome do tipo completo (incluindo tipos exteriores se aninhada).

Assim, você pode recuperar uma representação do tipo Integer (na forma de um TRttiType) com context.FindType('System.Integer').

Mas este mecanismo não pode ser usado para recuperar instâncias de tipos genéricos que não foram instanciados em tempo de compilação; instanciação em tempo de execução requer a geração de código de tempo de execução.

Você sempre pode registrar seus tipos em algum tipo de registro (gerido por uma lista de string ou dicionário) e criar uma função de fábrica para, em seguida, retornar o objeto apropriado. Infelizmente você teria que saber com antecedência quais os tipos que você ia necessidade. Algo semelhante ao Delphi funciona RegisterClass e FindClass (na unidade de classes). Meu pensamento é colocar o tipo de modelo genérico para a lista diretamente.

Um exemplo de possível uso:

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

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

EDIT: Aqui está uma implementação específica simples usando um tDictionary de Generics.Collections para lidar com o armazenamento de registro ... Eu vou deixar extrair isso em métodos úteis como um simples exercício para o leitor.

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;

Outro EDIT: eu estava dando este algum pensamento na noite passada, e descobriu outra técnica que você pode fundir-se este conceito. Interfaces. Aqui está um exemplo nada fazer rápido, mas pode ser facilmente estendido:

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;

Claro que você teria que implementar o QueryInterface, métodos _AddRef e _Release e estender a interface para fazer algo mais útil.

Se você esquecer genéricos e tipos básicos, a função "RegisterClass" seria útil. Mas ele não funciona para os genéricos ou tipos básicos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top