привет всем :) это мой первый вопрос в stackoverflow:)
в Delphi XE2 RTTI у нас есть класс TRttiMethod, и он имеет функцию CreateImplementation()
, которая позволяет динамически создавать процедуру или функцию с той же сигнатурой и анонимным методом, что и ее тело.
используя TRttiContext.getMethods()
/ getMethod()
мы можем получить коллекцию методов класса - коллекцию TRttiMethod.
Документация гласит (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod): не создавайте TRTTiMethod напрямую, а используйте getMethods () для получения его экземпляров.
Итак, если у нас есть экземпляр TRTTIMethod
, мы можем динамически создать метод с той же сигнатурой и вызвать его позже.
вопрос в том ..
например, у нас есть TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent))
возвращает TRttiType
объект экземпляра, который имеет typekind = tkMethod
.
мы знаем, что подпись TNotifyEvent является процедурой (отправитель: TObject) объекта;
возможно ли получить TRttiMethod
для этого? Я хочу динамически создать eventHandler для события, используя TRttiMethod.CreateImplementation()
или может быть есть другой способ динамически создавать реализацию метода?
PS: идея в том, чтобы создать что-то вроде цепочки событий. Во время компиляции мы не знаем тип события / сигнатуру, поэтому мы можем использовать для этого дженерики, например TEvenChain . Цепочка имеет коллекцию зарегистрированных обработчиков событий, поэтому, поскольку мы не знаем тип обработчика во время компиляции, мы должны создать его динамически, и этот обработчик только получает свои параметры и вызывает зарегистрированный обработчик с ними.
Обновление:
Вот некоторый код (идея заключается в создании цепочки обработчиков событий):
procedure TMainForm.FormCreate(Sender: TObject);
begin
FEventChain := TNotifyChain.Create();
FEventChain.AddHandler(event1);
FEventChain.AddHandler(event2);
TestButton.OnClick := FEventChain.EventHandler;
end;
Event1
& event2
- методы (sender : TObject)
формы;
это не общий пример (в данном случае T - NotifyEvent / TChain )
TEventChain.EventHandler
тоже TNotifyEvent
TNotifyChain
is
TNotifyChain = class(TObject)
strict private
FEvent : TNotifyEvent;
FItems : TList<TNotifyEvent>;
FCtx : TRttiContext;
public
procedure TestNotifyHandler(sender : TObject); virtual; abstract;
constructor Create();
procedure AddHandler(eh : TNotifyEvent);
property EventHandler : TNotifyEvent read FEvent;
end;
Свойство
EventHandler
сопоставлено с переменной FEvent
. И FEvent
не назначен, так как мы предполагаем, что тип события / обработчика неизвестен.
поэтому в конструкторе мы создаем виртуальный метод с подписью TNotifyEvent
и присваиваем его коду FEvent
:
constructor TNotifyChain.Create();
var st: TRttiType;
//et : TRttiMethodType;
Callback : TMethodImplementationCallback;
rttiMethod : TRttiMethod;
m : TMethod;
mi : TMethodImplementation;
begin
inherited;
FItems := TList<TNotifyEvent>.Create();
FCtx := TRttiContext.Create();
//et := FCtx.GetType(typeinfo(TNotifyEvent)) as TRttiMethodType;
st := FCtx.GetType(self.ClassType);
rttiMethod := st.GetMethod('TestNotifyHandler');
Callback := procedure(UserData: Pointer;
const Args: TArray<TValue>;
out Result: TValue)
var i : integer;
e : TMethod;
begin
for i := 0 to FItems.Count - 1 do begin
e := TMethod(Fitems[i]);
result := Invoke(e.Code, args, rttiMethod.CallingConvention, nil);
end;
end;
mi := rttiMethod.CreateImplementation(self, Callback);
m.data := self;
m.Code := mi.CodeAddress;
FEvent := TNotifyEvent(m);
end;
здесь я использую TestNotifyHandler
метод для создания фактического обработчика с той же сигнатурой, используя TRttimethod.CreateImplementation()
поэтому, я полагаю, есть способ создать реализацию обработчика событий во время выполнения, используя TRttiMethodType
из TNotifyEvent
, потому что он содержит информацию о типе / числе параметров и соглашении о вызовах фактического используемого события (в общем случае).