Передача методов в качестве параметров в десериализованной форме без ClassType - PullRequest
1 голос
/ 27 июля 2010

Я пытаюсь десериализовать форму.

Один из объектов в сериализованной форме имеет метод, который принимает серию событий в качестве параметров.

Теперь, когда у меня нет типа класса объекта при десериализации, у меня есть метод для объекта, выполняющего десериализацию, называемый AddMethod, который объявлен так:

procedure TMyDeserializer.AddMethod(ControlName, EventName: String;
  MethodAddr: Pointer);
var
    TargetControl : TControl;
    Method : TMethod;
begin
    if Not Assigned(TempForm) then
        Exit;
    if TempForm.Name = ControlName then
        TargetControl := TempForm
    else
        TargetControl := TempForm.FindChildControl(ControlName);

    if Assigned(TargetControl) then
    begin
        Method.Code := MethodAddr;
        Method.Data := TargetControl;
        SetMethodProp(TargetControl, EventName, Method);
    end;
end;

Чтобы я мог вставлять подпрограммы в различные элементы управления при десериализации их, проблема в том, что мне нужно добавить события в виде списка параметров (не в элемент управления). например, * +1008 *

SetUpEvents(EventHandler1:TNotifyEvent;EventHandler2:TNotifyEvent);

Где EventHandler1 и EventHandler2 определены где-то в коде как

Procedure EventHandler1(Sender:TNotifyEvent);  
begin
    // Do something
end;

Это не методы, а отдельные подпрограммы.

Когда я назначаю их объектам, подпрограмма не обязательно должна быть частью объекта, поскольку процедура AddMethod обрабатывает ее с помощью вызова, подобного

MyDeserializerInstance.AddMethod('Button1','OnClick',@EventHandler1);

Это работает для стандартных обработчиков событий, таких как Button1.OnClick, но не, если я хочу сделать

Procedure SetUpButton1Click(Method: TNotifyEvent)
begin
    TButton(MyDeserializerInstance.TempForm.FindChildControl('Button1')).OnClick = Method;
end;

Проблема в том, что я не могу передать подпрограмму как метод в пример процедуры установки.

Создаваемая форма не объявляется в интерфейсе и полностью определяется файлом, из которого она читается, а также несколькими отдельными подпрограммами в коде.

Итак, я полагаю, что вопрос заключается в том, как превратить подпрограмму в метод во время выполнения (после создания объекта, частью которого он должен быть), и если я не могу этого сделать, как передать подпрограммы в коде? как параметры в другом методе?

До сих пор я пытался привести TMethod как правильный тип события и заполнить .Data как TempForm. Он вызвал правильный метод, но зашифровал параметры.

Delphi версия 2007

Ответы [ 3 ]

4 голосов
/ 28 июля 2010

Нестатические методы класса имеют скрытый Self входной параметр, который заполняется при вызове метода.Вот чему соответствует поле TMethod.Data.Чтобы использовать автономную процедуру в качестве обработчика для события, которое ожидает метод класса, в процедуре должен быть определен дополнительный параметр, представляющий параметр Self, поэтому значение TMethod.Data должно куда-то идти, то есть:

procedure Button1ClickHandler(Self: Pointer; Sender: TObject);
begin 
  // Do something 
end; 

MyDeserializerInstance.AddMethod('Button1', 'OnClick', @Button1ClickHandler);

Ваша реализация AddMethod () назначает TargetControl в качестве значения TMethod.Data, поэтому приведенные выше параметры Self и Sender будут указывать на один и тот же объект во время выполнения, но это нормально.

Без явно заданного параметра Self, это объясняет, почему ваши параметры «зашифровываются», когда процедура вызывается во время выполнения.Скрытое значение Self присваивается параметру Sender, а действительное значение Sender игнорируется.

0 голосов
/ 28 июля 2010

Вы не «делаете метод» во время выполнения.Это было бы равносильно компиляции нового кода.Методы, которые вы назначаете различным свойствам событий, уже должны существовать.

Кроме того, вы не можете "добавлять события".У объекта, который вы десериализуете, уже есть события.Вы определили их, когда написали объявление класса в своем коде Delphi.Вы не можете добавить новые свойства события в класс после его компиляции.

Похоже, что вы действительно говорите, что у вас есть отдельная процедура , которую вы случайно назвалиMethod1, и вы хотите передать его как TNotifyEvent параметр при вызове SetUpMethods.

Это неправильный путь.Эта Method1 процедура не является методом, несмотря на его имя, поэтому вы не должны использовать его там, где требуется метод.Измените это объявление, чтобы оно принадлежало классу , и тогда оно будет методом.

Если вы не хотите создавать экземпляр класса, к которому принадлежит метод, это нормально- вы можете объявить его как метод класса вместо:

class procedure TSomeClass.Method1(Sender: TNotifyEvent);

Я рекомендую вам изменить объявление AddMethod, чтобы последний параметр имел тип TMethod.Тогда вы обязательно должны иметь как код, так и части данных указателя метода.Прямо сейчас вы назначаете часть данных на основе объекта, свойство события которого вы назначаете, но, как я уже упоминал в своем комментарии, такое отношение встречается редко, особенно сейчас, когда метод принадлежит совершенно не связанному классу (TSomeClass в моем примере).Значение поля TMethod.Data становится значением Self при вызове метода.Вы несете ответственность за обеспечение того, чтобы значение, которое вы храните в этом поле, было совместимого типа для класса, к которому принадлежит код.

0 голосов
/ 27 июля 2010

Я уверен, что кто-то исправит меня, если я ошибаюсь, но я не верю, что есть способ создать определение типа во время выполнения в нативном Delphi. RTTI Delphi просто пока не справляется с этим.

Два сценария, которые приходят на ум для сериализации объектов, - это постоянство и IPC. (Может быть, я еще и не подумал).

Сериализация DFM в Delphi будет примером постоянства. Если вы посмотрите на dfm, то заметите, что он вообще не определяет методы. Это просто назначение обработчиков событий свойствам, ожидающим обработчик событий. И обработчики, и свойства определяются во время разработки с использованием нормальных определений типов.

Если ваше намерение - IPC (будь то на той же машине или на удаленной), уже существуют платформы для этого. ( RemObjects приходит на ум)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...