Разработка обобщенного кода в Delphi 2010: работа с RTTI для экземпляров с интерфейсным ограничением
Вопрос, поставленный в контексте, касается возможности инспекции информации RTTI для экземпляра обобщенного типа с ограничением по интерфейсу. Обобщенные типы (generics) в Delphi позволяют создавать универсальные классы, которые могут работать с различными типами данных, удовлетворяющими определенным условиям. В данном случае, интересует работа с интерфейсами, что является неотъемлемой частью многих программ на Delphi, особенно в многокомпонентных проектах.
В примере кода, представленном в контексте, создается обобщенный класс TGenericClass<I: IMyObjectBase>, который предполагается использовать для работы с объектами, реализующими интерфейс IMyObjectBase. Внутри класса определена функция GetAttributeName, которая должна возвращать атрибут объекта, но при этом возникает ошибка компиляции, поскольку не удается получить RTTI информацию для объекта.
Решение проблемы
Для решения проблемы необходимо использовать кастинг интерфейса в объект, что возможно с версии Delphi 2010. Существует несколько подходов к решению:
Использование кастинга интерфейса в TObject с помощью оператора as:
pascal
for LAttr in LContext.GetType((AObject as TObject).ClassType).GetAttributes do
Этот метод работает в Delphi XE4 и выше.
Использование кастинга интерфейса в реализующий класс с помощью оператора as:
pascal
for LAttr in LContext.GetType((AObject as TMyObjectBase).ClassType).GetAttributes do
Также работает в Delphi XE4 и выше.
Создание метода в интерфейсе, который возвращает объект, и использование этого метода для инспекции объекта:
pascal
IMyObjectBase = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure DoSomething;
function GetObject: TObject; stdcall;
end;
Затем можно использовать полученный объект для работы с RTTI:
pascal
for LAttr in LContext.GetType(AObject.GetObject.ClassType).GetAttributes do
Альтернативный ответ
Также стоит отметить, что в Delphi 2010 для кастинга интерфейса в TObject необходимо немного помочь компилятору, используя синтаксис IInterface(AObject) as TObject или TObject(IInterface(AObject)).
Подтвержденный ответ
В итоге, после тестирования, было подтверждено, что следующие подходы работают:
Использование кастинга интерфейса в TObject с помощью оператора as (в Delphi XE5 и выше).
Использование метода GetObject в интерфейсе для получения объекта, с которым можно работать далее.
Пример кода
program Project3;
{$APPTYPE CONSOLE}
uses
RTTI,
SysUtils,
TypInfo;
type
TMyAttribute = class(TCustomAttribute)
strict private
FName: string;
public
constructor Create(AName: string);
property Name: string read FName;
end;
IMyObjectBase = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure DoSomething;
function GetObject: TObject; stdcall;
end;
TMyObjectBase = class(TInterfacedObject, IMyObjectBase)
public
procedure DoSomething; virtual;
function GetObject: TObject; virtual; override;
end;
// ... Остальной код ...
function TMyObjectBase.GetObject: TObject;
begin
Result := Self;
end;
function TGenericClass<I>.GetAttributeName(AObject: I): string;
var
LContext: TRttiContext;
LAttr: TCustomAttribute;
begin
Result := '';
LContext := TRttiContext.Create;
try
for LAttr in LContext.GetType(AObject.GetObject.ClassType).GetAttributes do
begin
if LAttr is TMyAttribute then
begin
Result := TMyAttribute(LAttr).Name;
Break;
end;
end;
finally
LContext.Free;
end;
end;
// ... Остальной код ...
var
LFirstObject: IMyObjectBase;
LSecondObject: IMyObjectBase;
LGeneric: TGenericClass<IMyObjectBase>;
begin
try
LFirstObject := TMyFirstRealClass.Create;
LSecondObject := TMySecondRealClass.Create;
LGeneric := TGenericClass<IMyObjectBase>.Create;
Writeln(LGeneric.GetAttributeName(LFirstObject));
Writeln(LGeneric.GetAttributeName(LSecondObject));
LGeneric.Free;
LFirstObject := nil;
LSecondObject := nil;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Заключение
Работа с обобщенными типами в Delphi требует внимания к деталям, особенно когда речь заходит о работе с RTTI. Важно помнить о возможности кастинга интерфейсов в объекты и использовать соответствующие методы для получения необходимой информации.
Вопрос связан с разработкой в Delphi 2010, где рассматривается использование RTTI для работы с обобщенными типами, имеющими интерфейсное ограничение, и поиск решения проблемы с получением информации RTTI для экземпляров таких типов.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.