2013-06-21 4 views
6

Допустим, у меня есть класс образец помощникаDelphi Класс Helper RTTI GetMethod

TSampleClassHelper = class helper for TSampleClass 
public 
    procedure SomeHelper; 
end; 

я делаю следующее:

var 
    obj :TSampleClass; 
begin 
    obj:=TSampleClass.Create; 
    obj.SomeHelper; 
end; 

и это работает, как ожидалось.

Но как я могу использовать RTTI для вызова вспомогательного метода? Следующая работа не работает, GetMethod возвращает нуль.

var 
    obj :TSampleClass; 
    ctx :TRTTIContext; 
    rtype :TRTTIType; 
    rmethod :TRTTIMethod; 
begin 
    obj:=TSampleClass.Create; 
    rtype:=ctx.GetType(obj.ClassType); 
    rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil ! 
end; 

Так что RTTI не работает для методов, определенных в помощниках классов? Во всяком случае, вокруг?

Спасибо.

+0

я вижу, но в моей реальной жизни кода я тестирование на «SomeMethod» против любого произвольного объекта. Я не знаю, имеет ли объект метод, определенный с помощью помощника или нет.Поэтому я думаю, что это не будет работать для «SomeMethod», определенного через помощник класса. Ну что ж. –

ответ

8

Причина, по которой ваш код возвращает метод nil, заключается в том, что тип объекта не содержит метода с именем SomeHelper. Тип, который содержит этот метод, является вспомогательным типом.

Таким образом, вы могли бы написать это, который будет возвращать метод не-ноль:

obj:=TSampleClass.Create; 
rtype:=ctx.GetType(TypeInfo(TSampleClassHelper)); 
rmethod:=rtype.GetMethod('SomeHelper'); 

Конечно, вы должны сразу увидеть первую проблему, а именно использование указанного времени компиляции типа, TSampleClassHelper. Можем ли мы использовать RTTI для обнаружения TSampleClassHelper во время выполнения в зависимости от типа экземпляра? Нет, мы не можем, как я объясню ниже.

Даже если мы поместим это в одну сторону, насколько я могу видеть, нет способа вызвать метод с использованием RTTI. Если вы вызываете rmethod.Invoke(obj, []), тогда код в TRttiInstanceMethodEx.DispatchInvoke блокирует попытку вызова вспомогательного метода. Он блокирует его, потому что он указывает, что тип экземпляра несовместим с классом метода. Соответствующий код:

if (cls <> nil) and not cls.InheritsFrom(TRttiInstanceType(Parent).MetaclassType) then 
    raise EInvalidCast.CreateRes(@SInvalidCast); 

Ну, вы можете получить код адрес вспомогательного метода с rmethod.CodeAddress, но вам нужно найти какой-то другой способ вызвать этот метод. Достаточно легко передать его методу с соответствующей сигнатурой и вызвать его. Но зачем в любом случае беспокоиться с rmethod.CodeAddress? Почему бы не использовать TSomeHelperClass.SomeMethod и вырезать RTTI из петли?

Обсуждение

разрешение Helper выполняется статически на основе активного помощника в точке компиляции. Когда вы пытаетесь вызвать вспомогательный метод с использованием RTTI, нет active helper. Вы уже давно закончили компиляцию. Поэтому вам нужно решить, какой класс помощника использовать. В этот момент вам не нужен RTTI.

Основная проблема здесь заключается в том, что разрешение класса-помощника класса является в основном статическим процессом, выполняемым с использованием контекста компилятора. Поскольку во время выполнения нет контекста компилятора, разрешение метода вспомогательного класса класса не может быть выполнено с использованием RTTI.

Для большего понимания в этом есть Распознать ответ Аллена Бауэра здесь: Find all Class Helpers in Delphi at runtime using RTTI?

+0

Это не значит, что для класса есть несколько помощников. Это то, что некоторые классы имеют необходимый метод, определенный помощником, а некоторые нет. Например, для TStrings я добавил метод через помощник, но для TMyClass он определяется непосредственно в классе. –

+0

@ AJ. Реальная проблема заключается в том, что решение вспомогательного метода выполняется статически компилятором на основе контекста компиляции. Эта концепция полностью ортогональна RTTI. –

 Смежные вопросы

  • Нет связанных вопросов^_^