![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вызов функции из функции [D7, XP]
Сергей © (2011-01-14 22:08:00)Вызов функции из функции
Код такой:
type
TGetMy = procedure() of object;
function MyFunc1(OnGetMy : TGetMy = nil): Boolean;
procedure EvOnChange(Self, Sender: TObject);
begin
if Assigned(OnGetMy) then OnGetMy(); // Âòîðîé âûçîâ.
end;
var
Form : TForm;
EvChange : TMethod;
begin
if Assigned(OnGetMy) then OnGetMy(); // Ïåðâûé âûçîâ.
Form := TForm.Create(Application);
with Form do begin
with TEdit.Create(Form) do begin
Parent := Form;
EvChange.Code := @EvOnChange;
OnChange := TNotifyEvent(EvChange);
end;
// ...
end;
end;
Проблема в том, что первый вызов OnGetMy проходит, а второй из функции EvOnChange вызывает ошибку Дельфи. Вопрос, как сделать вызов правильно, чтобы ошибки не возникало?
Leonid Troyanovsky (2011-01-18 22:22:00) [1]
> DiamondShark © (18.01.11 20:19) [55]
> Вот простого надёжного решения ты не хочешь, а хитроподвыперднутое
> глюкалово ты хочешь.
Так понятней.
Хорошо описано.
--
Regards, LVT.
DiamondShark (2011-01-18 20:19:00) [2]
> Сергей (18.01.11 18:40) [52]
> "Не положено" и "невозможно" - это разные вещи.
Не положено сохранять (вне контекста определения) указатель на локальную функцию, потому что невозможно (вне контекста определения) её вызвать.
Так понятнее?
Отсюда следует, что для того, чтобы её-таки вызвать, тебе понадобится сделать захват и восстановление контекста.
Для захвата тебе понадобится какая-нибудь структура, которая будет жить не меньше указателя на функцию (а контроль над ним ты теряешь прямо вот не одходя от кассы, хе-хе).
А для восстановления тебе придётся проэмулировать стековый фрейм.
Вот простого надёжного решения ты не хочешь, а хитроподвыперднутое глюкалово ты хочешь.
Тебе больше делать нехер? Времени свободного много? Ну сходи с тёлками потуси.
sniknik (2011-01-18 19:14:00) [3]> Разве в ява или яваскрипте есть вложенные функции?
в яве не уверен, не писал на ней, а вот в яваскрипте... вот про что говорил
http://javascript.ru/basic/closure
думаю примеров там для ответа на этот вопрос достаточно.
Плохиш (2011-01-18 18:43:00) [4]
> ... есть еще возможность ..., переходи на яву, хотя, нет,
> точно за нее не скажу, на яваскрипт, вот там точно, такое
> в порядке вещей.
Разве в ява или яваскрипте есть вложенные функции?
Сергей (2011-01-18 18:40:00) [5]
> Servy © (17.01.11 05:45) [49]
>
> > Опять не то. Задача вызвать функции OnGetMy из функции
> MyFunc1,
> > а не просто прописать её в OnChange.
>
> Это невозможно. Указатели на локальные процедуры и функции
> не положено сохранять.
"Не положено" и "невозможно" - это разные вещи.
KSergey (2011-01-17 08:53:00) [6]> Сергей (17.01.11 04:29) [47]
> Все эти личностные оценки правильно или не правильно давайте оставим в стороне.
Где здесь личностные оценки?!
sniknik (2011-01-17 08:14:00) [7]> Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1, а не просто прописать её в OnChange.
тебе же объяснили причину, она локальная(/адрес), сделай ее глобальной и сможешь указать, и ее (а переменную сохранять рядом как в [4] например).
или опять не то? т.е. уперся в один, невозможный вариант, и "решаешь" его. а нужно решать задачу. а варианты менять, а лучше изначально использовать правильные.
... есть еще возможность ..., переходи на яву, хотя, нет, точно за нее не скажу, на яваскрипт, вот там точно, такое в порядке вещей. неважно где описана процедура ее можно назначить любому событию (там это даже используется сделать "типа объекта со своим списком переменных").
Servy (2011-01-17 05:45:00) [8]
> Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1,
> а не просто прописать её в OnChange.
Это невозможно. Указатели на локальные процедуры и функции не положено сохранять. Если вы попробуете скомпилировать следующий код:
procedure Test;
procedure Local;
begin
ShowMessage('I am local');
end;
var
P: TProcedure;
begin
P := Local;
end;
То увидите вполне закономерное сообщение об ошибке:
E2094 Local procedure/function 'Local' assigned to procedure variable
Однако, операцию взятия адреса у локальных процедур разработчики компилятора почему-то не запретили (вероятно напрасно). Однако, при таком вызове (через сохраненный указатель) по вполне объективным причинам обращаться к локальным переменным (включая параметры, такие как OnGetMy) родительской функции вы не сможете.
Решение вам предлагалось еще в [15]:
> в данной конкретной ситуации способ простой, не использовать
> локальную (стековую) переменную при вызове ее в кода в другом
> месте. а сохранить ее где нибудь в доступном из обоих мест
> месте, например.
> (говорил же просто)
Если оно вас по каким-то причинам не устраивает, то, судя по всему, у задачи в вашей постановке решения нет (так как по постановке задачи нельзя отменить локальность функции, а жестокая реальность не дает обращаться к стековым переменным родительской функции, если дочерняя вызывается черт знает откуда).
Германн (2011-01-17 05:15:00) [9]
> Задача вызвать функции OnGetMy из функции MyFunc1, а не
> просто прописать её в OnChange.
А ТС продолжает настаивать на своём бреде. :(
Сергей (2011-01-17 04:29:00) [10]
> sniknik © (15.01.11 20:50) [17]
> замени
> EvChange.Code := @EvOnChange;
> OnChange := TNotifyEvent(EvChange);
> на
> OnChange := TNotifyEvent(OnGetMy); (сохраним переменную
> собственно в объекте)
> и все будет работать
Опять не то. Задача вызвать функции OnGetMy из функции MyFunc1, а не просто прописать её в OnChange.
> Юрий Зотов © (16.01.11 08:46) [20]
>
> А ответ на вопрос "как правильно осуществить вызов из примера
> в первом постинге" все же имеется.
>
> Отвечаю: правильно - никак.
Ничего. Все эти личностные оценки правильно или не правильно давайте оставим в стороне.
Leonid Troyanovsky (2011-01-17 04:06:00) [11]
> Servy © (17.01.11 02:44) [43]
> Да. Однако на обсуждаемую спорную ошибку в [22] это никак
> не влияет, негоже сделать вид, что там все окей, позволив
> возможным неопытным читателям этой ветки обмануться, не
> так ли?
По ходу обсуждения я заметил не одну неточность в формулировках,
но не спешил их уточнять, бо поведение ТС к тому не располагало.
ЮЗ, IMHO, имел в этом случае право и на умышленную неточность.
Ну, а так, конечно, да - все люди ошибаются, и указывать на ошибки
святое форумное дело.
--
Regards, LVT.
Servy (2011-01-17 03:38:00) [12]
> Вы скачали пример по ссылке в Юрий Зотов © (16.01.11 20:
> 08) [26]?
> Вы его проверили? Он работает?
Да, он работает. Как это подтверждает отсутствие в нем обсуждаемой ошибки, явно сформулированной мной в [41]?
> Однако, не стоит обсуждать тут пост [22], если у вас нет
> намерения "поспорить с ЮЗ".
Я не пониманию, исходя из чего единственным допустимым поводом обсуждения поста является намерение "поспорить с ЮЗ". Я против него в целом ничего не имею, все люди ошибаются. Другое дело, что тут почему-то появились люди, упорно утверждающие, что так и надо.
Германн (2011-01-17 03:16:00) [13]
> Да. Однако на обсуждаемую спорную ошибку в [22] это никак
> не влияет, негоже сделать вид, что там все окей, позволив
> возможным неопытным читателям этой ветки обмануться, не
> так ли?
Вы скачали пример по ссылке в Юрий Зотов © (16.01.11 20:08) [26]?
Вы его проверили? Он работает?
Однако, не стоит обсуждать тут пост [22], если у вас нет намерения "поспорить с ЮЗ".
Servy (2011-01-17 02:44:00) [14]
> Сам сабж - бредовый.
Да. Однако на обсуждаемую спорную ошибку в [22] это никак не влияет, негоже сделать вид, что там все окей, позволив возможным неопытным читателям этой ветки обмануться, не так ли?
Германн (2011-01-17 02:36:00) [15]
> Германн © (17.01.11 01:58) [37]
>
>
> > Вообще-то, если решать задачу
>
> А нужно ли решать эту задачу в "Начинающим"?
> Да ещё и разводить теоретический спор на тему этой задачи?
>
> Сам сабж - бредовый. X-Y-Z
>
Servy (2011-01-17 02:33:00) [16]
> Ega23 © (17.01.11 01:10) [33]
> Он будет показывать ровно то, что должен показывать. Задачи,
> чтобы это был полноценный TNotifyEvent не было.
Конечно, задача ведь была "сделайте мне как можно более неполноценный TNotifyEvent".
> sniknik © (17.01.11 02:09) [40]
> или имеется в виду второй случай с Memo? ну так бысмысленным
> сделал его тот кто вручную составлял и составил неправильно,
> дал Mem-У Edit. ССЗБ.
Я правильно вас обоих понял: то, что явный параметр TNotifyEvent - Sender - потерян и не доступен из процедуры, а неявный параметр - Self - переименован в Sender не является ошибкой в коде [22], а, напротив, является отличным примером написания кода для начинающих? Тогда будет замечательно, если вы потрудитесь обосновать это нелепое с моей точки зрения утверждение.
sniknik (2011-01-17 02:09:00) [17]> Self-ом не являющийся.
или имеется в виду второй случай с Memo? ну так бысмысленным сделал его тот кто вручную составлял и составил неправильно, дал Mem-У Edit. ССЗБ.
sniknik (2011-01-17 02:06:00) [18]> если решать задачу замены метода на регулярную процедуру
я вообще то изначально был против ее решать... проще/лучше описать типом/классом (что ни добавляет ни байта к коду), чем составлять "вручную" в коде, и утяжелять его.
посмотри примеры [3], [4].
> Ну и для чистоты концепции неплохо бы передавать в Self именно nil, а не бессмысленную ссылку на объект, Self-ом не являющийся.
почему это она бессмысленная? раз объект существует (обьект Edit создали? создали) то есть (должна быть раз предусмотрена) и ссылка на него, но если хочешь добавь в любой пример ([3], [4]) слово class перед procedure и "цель" достигнута.
Servy (2011-01-17 02:02:00) [19]
> что "сдвигает" параметр, а не меняет их местами из-за имени.
> т.е. ну, чтобы вам было привычнее напишите так
> procedure Proc(Self: TObject);
Я бы и написал Self, и второй параметр там оставил. Но Юрий Зотов написал там именно Sender. Таким образом, новичок бы логично предположил, что туда передается именно Sender. В коде [22] разницы нет, так как Sender = Self, поэтому я привел другой пример в [32], где Sender и Self различаются. Соответственно, возникает вопрос, намеренно ли в [22] написан Sender (и если так, то зачем, ветка то для начинающих), или это ошибка, которую следует поправить.
Злобный буратино то не я, а автор кода. Я лишь продемонстрировал, что в Sender'е оказывается совсем не Sender, что должно было навести на некоторые мысли доблестного защитника кода из [22], который уверен, что в никаких проблем с сим кодом не наблюдается.
Ваши объяснения того, что происходит мне не были нужны, однако надеюсь пригодятся кому-нибудь из начинающих.
Германн (2011-01-17 01:58:00) [20]
> Вообще-то, если решать задачу
А нужно ли решать эту задачу в "Начинающим"?
Да ещё и разводить теоретический спор на тему этой задачи?
Сам сабж - бредовый. X-Y-Z