Вопрос

Учитывая текстовую строку, содержащую имя типа, есть ли какой-нибудь способ получить сам соответствующий тип?

Я хочу сделать что-то вроде этого:

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

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

Я просмотрел несколько объяснений RTTI онлайн и просмотрел модули Delphi и не вижу того, что я ищу.Возможно ли это?

Это было полезно?

Решение

Нет, дженерики полностью рассчитаны на компиляцию.

Другие советы

Новый модуль RTTI в Delphi 2010 имеет способ извлечения типов, объявленных в разделе интерфейса units.Для любого заданного типа, представленного TRttiType например, в TRttiType.QualifiedName свойство возвращает имя , которое может быть использовано с TRttiContext.FindType позже, чтобы получить тип.Квалифицируемое имя - это полное имя модуля (включая пространства имен, если они существуют), за которым следует '.', за которым следует полное имя типа (включая внешние типы, если они вложенные).

Таким образом, вы могли бы получить представление целочисленного типа (в виде TRttiType) с context.FindType('System.Integer').

Но этот механизм не может быть использован для извлечения экземпляров универсальных типов, которые не были созданы во время компиляции;создание экземпляра во время выполнения требует генерации кода во время выполнения.

Вы всегда можете зарегистрировать свои типы в каком-нибудь реестре (управляемом списком строк или словарем) и создать заводскую функцию, которая затем вернет соответствующий объект.К сожалению, вам пришлось бы заранее знать, какие типы вам понадобятся.Что-то похожее на функции Delphi RegisterClass и FindClass (в блоке classes).Мое мышление состоит в том, чтобы поместить общий тип шаблона непосредственно в список.

Пример возможного использования:

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

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

Редактировать: Вот конкретная простая реализация с использованием TDictionary из Generics.Коллекции для обработки хранилища реестра...Я оставлю извлечение этого в полезные методы в качестве простого упражнения для читателя.

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;

Еще одна ПРАВКА: Вчера вечером я немного подумал над этим и обнаружил еще одну технику, которую вы можете объединить с этой концепцией.Интерфейсы.Вот краткий пример бездействия, но его можно легко расширить:

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;

конечно, вам пришлось бы реализовать методы QueryInterface, _AddRef и _Release и расширить интерфейс, чтобы делать что-то более полезное.

Если вы забыли обобщения и базовые типы, функция "RegisterClass" была бы полезна.Но это не работает для дженериков или базовых типов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top