Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.11.23;
Скачать: CL | DM;

Вниз

Переменные процедурного типа   Найти похожие ветки 

 
checkmate-maker   (2008-10-14 12:45) [0]

Здравствуйте, знатоки.
 Помогите, пожалуйста, разобраться с задачей проверки корректности присваивания.
 Имеется код:

...
var
 f: procedure(a0: Integer; a1:String); stdcall;
begin
 @f := GetPtr();
end;

 Функция GetPtr возвращает указатель на процедуру(либо функцию). Если параметры процедуры f идентичны параметрам в возвращенной процедуры, то все нормально. Если совпадение не достигнуто, то ненормально. Как до вызова f определить корректность параметров?
 Спасибо.


 
clickmaker ©   (2008-10-14 12:54) [1]

а почему может возникнуть несовпадение?


 
Сергей М. ©   (2008-10-14 12:56) [2]


> до вызова f определить корректность параметров?


До вызова f нет никаких параметров, кроме формальных.


 
Сергей М. ©   (2008-10-14 13:01) [3]


> Функция GetPtr возвращает указатель на процедуру(либо функцию)


Делай так

type
 TMyProc = procedure(a0: Integer; a1:String); stdcall;
var
f: TMyProc;

function GetPtr(): TMyProc;

и ни о чем не задумывайся - чуть что не так, умный компилятор тут же даст по рукам)


 
Slym ©   (2008-10-14 13:08) [4]

Я чищу зубы... как мне удостовериться что я в рот засунул щетку а не строл дробовика? И что это за странный рычажок на моей щетке?


 
checkmate-maker   (2008-10-14 13:22) [5]


> Я чищу зубы... как мне удостовериться что я в рот засунул
> щетку а не строл дробовика? И что это за странный рычажок
> на моей щетке?


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


 
checkmate-maker   (2008-10-14 13:25) [6]


> Сергей М.

 Спасибо, Сергей. Но хочу уточнить, реальная ситуация диктует, что функция GetPtr параметризована(мои извинения, что не обрисовал это сразу), возвращает указатели на разные процедуры(функции) - Что делать в этом случае?


 
Slym ©   (2008-10-14 13:31) [7]

checkmate-maker   (14.10.08 13:25) [6]
я застрелил тебя из щетки


 
clickmaker ©   (2008-10-14 13:40) [8]

> функция GetPtr параметризована(мои извинения, что не обрисовал
> это сразу), возвращает указатели на разные процедуры(функции)

каждый раз с разным числом параметров?


 
Сергей М. ©   (2008-10-14 14:00) [9]


> checkmate-maker   (14.10.08 13:25) [6]


Возвратив pointer ты сознательно "обезличил" подпрограмму.
Получить в ран-тайм инф-цию о прототипе подпрограммы, точка входа в которую представлена нетипизированным указателем, невозможно.


 
checkmate-maker   (2008-10-14 14:04) [10]


> каждый раз с разным числом параметров?

Совершенно верно. По сути дела в зависимости от параметра возвращает разные процедуры. Например если параметр = 0, то это процедура без параметров, если = 1, то с одним. Понимаю, что в зависимости от параметра следует использовать разное объявление переменной f, но хочется подстраховаться перед вызовом f, хочется знать, на процедуру с каким числом и каких параметров воззвращен указатель.
 Надеюсь, большой текст не затуманит мысль.
 Спасибо.


 
clickmaker ©   (2008-10-14 14:09) [11]

> Например если параметр = 0, то это процедура без параметров,
> если = 1, то с одним

заведи массив указателей на процедуры
параметр сделай индексом в нем


 
oxffff ©   (2008-10-14 14:22) [12]


> возвращает указатели на разные процедуры(функции) - Что
> делать в этом случае?


Контракт этих процедур совпадает?


 
Сергей М. ©   (2008-10-14 14:24) [13]


> хочется подстраховаться перед вызовом f


А чего собственно ты боишься, коли о страховке задумался ?


 
checkmate-maker   (2008-10-14 14:37) [14]


> А чего собственно ты боишься, коли о страховке задумался
> ?


Интерфейс процедур в библиотеке меняется чуть реже, чем заходит солнце. Сложно быть уверенным в том, что завтра у процедуры в библиотеке не добавиться/убавиться еще один параметр, измениться тип. Хочется отловить эту ситуацию.
 Пока, чувствую, самое верное из форума - это фраза:

> Возвратив pointer ты сознательно "обезличил" подпрограмму.

 Видимо, придется пользоваться try..except.


 
oxffff ©   (2008-10-14 14:41) [15]


> По сути дела в зависимости от параметра возвращает разные
> процедуры. Например если параметр = 0, то это процедура
> без параметров, если = 1, то с одним. Понимаю, что в зависимости
> от параметра следует использовать разное объявление переменной
> f, но хочется подстраховаться перед вызовом f, хочется знать,
>  на процедуру с каким числом и каких параметров воззвращен
> указатель.


Этот подход совершенно не выразителен и небезопасен.
Если возвращаемые функции известны в Compile time, то тебе нужно сделать

TGetProc<T>=function GetProc(idx:integer):T;
TMyProc2 = procedure(a0: Integer; a1:String); stdcall;
TMyProc3 = procedure(a0: Integer; a1:String;a2:String;); stdcall;

a:TGetProc<TMyProc2>;
a:TGetProc<TMyProc3>;
begin

//Сделать жесткое присваивание.
Честно говоря не пробовал но Barry использует "очень жесткое" при generics.Collections, а точнее
a:= @GetPtr
b:=@GetPtr

a(2)(1,"2")
b(3)(1,"2","3")

Надеюсь идею понял. :)


 
oxffff ©   (2008-10-14 14:46) [16]


> checkmate-maker   (14.10.08 14:37) [14]


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

UnyCall=class
procedure UnyCall;virtual;abstract;
end;

UnyCall2=class(UnyCall)
protected
a:integer;b:string;
procedure UnyCall;virtual;abstract;
constructor (a:integer;b:string);
procedure UnyCall;override;
end;

constructor (a:integer;b:string);
begin
self.a:=a;
self.b:=b;
end;

procedure UnyCall;override;
begin
use A,b here
end;

Вызов такой.

var a:UnyCall;

a:=UnyCall2.create(1,"2")

a.unycall();
...

Идея понятна?


 
oxffff ©   (2008-10-14 14:47) [17]


> a:TGetProc<TMyProc2>;
> a:TGetProc<TMyProc3>;


> a:TGetProc<TMyProc2>;
> b:TGetProc<TMyProc3>;


 
Сергей М. ©   (2008-10-14 14:50) [18]


> Видимо, придется пользоваться try..except


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

Может быть, есть резон обратить взор на ole-автоматизацию и диспинтерфейсы ?


 
oxffff ©   (2008-10-14 14:51) [19]


> Честно говоря не пробовал но Barry использует "очень жесткое"
> при generics.Collections.defaults, а точнее


cм.
Generics.Defaults;

функция создания объекта нештатными средствами.
function MakeInstance(vtable: Pointer; sizeField: Integer): Pointer;


 
oxffff ©   (2008-10-14 14:58) [20]

Могу еще предложить вариант

IGetParameterCallBack=interface
function GetParameter(idx:integer,var param):boolean;
end;

TUnyProc=function (const GetParameter:IGetParameterCallBack):integer;

function MyProc(const GetParameter:IGetParameterCallBack):integer;
var a:integer;
    b:string;
begin
if not GetParameter.GetParameter(1,a) then showmessage("No params");
if not GetParameter.GetParameter(2,b) then showmessage("No params");
....
end;


 
Сергей М. ©   (2008-10-14 14:58) [21]


> oxffff


Какие контракты, какие функторы ?
Ты сейчас с кем разговариваешь ?)
У человека D7, а ты ему про функторы да про сфинктеры)


 
checkmate-maker   (2008-10-14 15:00) [22]


> Параметры из объекта окружения, так называемый функтор.


> Идея понятна?

Спасибо, но непонятно как связать построенную Вами ООМ c моей задачей.
Объявлять методы в одном классе, а реализовывать в его наследниках я, к счастью, умею.
Спасибо за термин "функтор"  - почитаю.


 
oxffff ©   (2008-10-14 15:00) [23]


> Сергей М. ©   (14.10.08 14:58) [21]


oxffff ©   (14.10.08 14:46) [16]
oxffff ©   (14.10.08 14:58) [20]

Штатно реализуются в D7.

P.S. Жаль что вы только про сфинкторы знаете. :)


 
Сергей М. ©   (2008-10-14 15:09) [24]


> oxffff ©   (14.10.08 15:00) [23]

Я про [15])


 
oxffff ©   (2008-10-14 15:10) [25]


> Сергей М. ©   (14.10.08 15:09) [24]


А...
Дык я стараюсь не ограничиваться одним вариантом решения. :)


 
Сергей М. ©   (2008-10-14 15:16) [26]


> checkmate-maker   (14.10.08 15:00) [22]


Проверку на соответствие кол-в и типов ожидаемых и фактически переданных параметров можно отдать на откуп любому готовому механизму маршаллинга диспинтерфейсных вызовов. При несовпадении он возбудит соответствующее исключение.


 
oxffff ©   (2008-10-14 15:23) [27]


> Сергей М. ©   (14.10.08 15:16) [26]


Могу упростить решение до минимума.

TCallContext=class
end;

TCallContextIntegerAndString=class
a:integer;
b:string;
end;

procedure Myfunc(a:TCallContext);
begin
if a is TCallContextIntegerAndString then
 else
 begin
 Showmessage("Not valid context");
 exit;
 end;
end;


 
checkmate-maker   (2008-10-14 15:29) [28]

Спасибо Всем за участие в дискуссии.
Воспользоюсь тем, что параметры процедур в библиотеке храняться в БД(об этом я промолчал намеренно - без обид), создам фунцию, следующего вида
function MayConnectToFunc(aFuncIdent: WideString; aParamArray: array of String; aIsFunc: Boolean = False): Boolean;
здесь aFuncIdent - точка входа в процедуру(параметр, который я использую при вызове GetPtr, описанный выше);
aParamArray - массив с типами параметров в согласовании с порядком следования; Также можно использовать TStringList.
aIsFunc-флажок, что это функция и последнее значение в массиве - это тип возвращаемого значения.


 
Сергей М. ©   (2008-10-14 15:32) [29]


> oxffff ©   (14.10.08 15:23) [27]


Не пойдет.
При любом чихе править придется и вызываемую и вызывающую сторону.


 
oxffff ©   (2008-10-14 15:33) [30]


> checkmate-maker   (14.10.08 15:29) [28]


Главное, чтобы работало. :)


 
oxffff ©   (2008-10-14 15:36) [31]


> Сергей М. ©   (14.10.08 15:32) [29]


Дык, и в вашем случае тоже самое.
В любом случае при расширении функции придется менять ее реализацию и место вызова. Хотите сказать что в вашем случае не так?


 
Сергей М. ©   (2008-10-14 15:41) [32]


> checkmate-maker   (14.10.08 15:29) [28]


Т.е. ты таки движешься по пути изобретения велосипеда)

Тогда уж, чтобы меньше возни было и для пущей универсальности:

function CallProcByName(AProcName, AParams: OleVariant): OleVariant; safecall;


 
Сергей М. ©   (2008-10-14 15:44) [33]


> oxffff ©   (14.10.08 15:36) [31]


Реализацию вызываемого кода - да.
А реализацию вызывающего кода - нет.
Вызываемый код известит исключением вызывающий код о любом несоответсвии, будь то имя точки входа и/или кол-во/типы параметров.


 
oxffff ©   (2008-10-14 15:46) [34]


> Сергей М. ©   (14.10.08 15:41) [32]


Этот вариант самый естественный, так же как и array of const.
Но с точки зрения эффективности, не самый удачный.
Поскольку большие дополнительные издержки.

>Т.е. ты таки движешься по пути изобретения велосипеда)

Я к счастью не Хейлсберг, но ответил бы так же как и он всегда отвечал на этот вопрос.


 
Сергей М. ©   (2008-10-14 15:55) [35]


> oxffff ©   (14.10.08 15:46) [34]


> с точки зрения эффективности, не самый удачный


А что делать ? Издержки интерпретации)

Хочешь универсальности и безопасности - плати за них сквозным снижением производительности..

По поводу же велосипеда - это ж не тебе было адресовано, а автору)


 
oxffff ©   (2008-10-14 15:56) [36]


> А реализацию вызывающего кода - нет.


Ведь лукавите.

Если в функции добавляется\удаляется параметр,
хотите сказать что в месте вызова не нужно его добавлять\удалять?
А как вы его хотите передать\удалить?
Придется внести изменения и в него тоже.
А в моем случае будет просто другой класс-контекст вызова.

То есть ваше
a:variant;
begin

a.SomeMethod(1,2,"222");
->
a.SomeMethod(1,2,"222",10...);


И в моем случае

TCallContextIntegerAndString.create(1,2,"222");
TCallContextOther.create(1,2,"222",10....);


Причем в моем случае проверка будет одна всего контекста вызова в целом, а вашем проверок как минимум равное количеству параметров, так что в мой велосипед все же быстрее. :)))


 
Сергей М. ©   (2008-10-14 16:16) [37]


> oxffff ©   (14.10.08 15:56) [36]


Да нафига мне в вызывающем коде что-то проверять перед вызовом ?)
Пусть этим занимается вызываемый код при вызове !

Ты же, вводя в адр.строку браузера URL, не проверяешь ведь ее актуальность и корректность с т.з., например, наличия и кол-ва параметров ?

Не проверяешь.

И браузер тоже не проверяет - ему это тоже нафих не надо, пусть проверкой занимается сам сервер.

Было:

someproto://somedomain/someresource?param1=A?param2=B

запрос успешно выполнялся, сервер возвращал рез-т, браузер исправно его представлял юзеру.

После того как "отцы" ресурса с какого-то бодуна взяли да добавили обязательный 3-й параметр при запросах к ресурсу, стало:

someproto://somedomain/someresource?param1=A?param2=B?param3=C

А я ничего не зная об этом по-прежнему запрашиваю с 2-мя параметрами.

Кто ответственен за возможную коррекцию моей ошибки или корректный отлуп запроса ?
Разумеется, сервер (вызываемый код) ! Не браузер же (вызывающий код) !
Иначе на каждый чих "отцов" придется переписывать каждый браузер)


 
Сергей М. ©   (2008-10-14 16:33) [38]


> oxffff


В конце-концов разработчик вызываемого кода, который часто чихает, но который уважает труд разработчика вызываемого кода, предоставляет (тем или иным образом) последнему полноценную своевременно обновляемую библиотеку типов, которую можно использовать как в компайл-тайм, так и в ран-тайм.


 
Slym ©   (2008-10-14 16:42) [39]

Тогда проще
type
 TProc=procedure(Params:array of const);

и типы разные и переменное число параметров


 
Сергей М. ©   (2008-10-14 16:51) [40]


> Slym ©   (14.10.08 16:42) [39]


А как результат возвращать, если это функция ?



Страницы: 1 2 вся ветка

Текущий архив: 2008.11.23;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.014 c
2-1223477519
Dr. Genius
2008-10-08 18:51
2008.11.23
MessageDlgPos


15-1222328712
nick
2008-09-25 11:45
2008.11.23
нужна помощь


10-1150752317
pooh
2006-06-20 01:25
2008.11.23
работа с Excel


11-1195771438
tigra
2007-11-23 01:43
2008.11.23
kol+vcl indy


15-1222233440
Slider007
2008-09-24 09:17
2008.11.23
С днем рождения ! 24 сентября 2008 среда