Форум: "Начинающим";
Текущий архив: 2008.11.23;
Скачать: [xml.tar.bz2];
ВнизПеременные процедурного типа Найти похожие ветки
← →
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]
А как результат возвращать, если это функция ?
← →
oxffff © (2008-10-14 17:18) [41]
> А я ничего не зная об этом по-прежнему запрашиваю с 2-мя
> параметрами.
Ну дык, а что мешет наследовать TCallContextOther от TCallContextIntegerAndString?
Где я ошибаюсь?
← →
oxffff © (2008-10-14 17:20) [42]
> Пусть этим занимается вызываемый код при вызове !
Он у меня как раз этим и занимается.
← →
Сергей М. © (2008-10-14 17:22) [43]
> Где я ошибаюсь?
Этот "наследник" д.б. известен как вызывающей, так и вызываемой стороне.
← →
Сергей М. © (2008-10-14 17:32) [44]
> oxffff
Ключевое здесь это:
> параметры процедур в библиотеке храняться в БД
Следует понимать, что инф-ция в БД может быть изменена в любой момент времени уже после разработки вызывающего кода, поэтому ни о каком компайл-тайм речи идти не может.
А твой подход с TCallContext и его наследниках требует именно компайл-тайм на обеих сторонах взаимодействия.
← →
oxffff © (2008-10-14 19:55) [45]
> Сергей М. © (14.10.08 17:22) [43]
>
> > Где я ошибаюсь?
>
>
> Этот "наследник" д.б. известен как вызывающей, так и вызываемой
> стороне.
Почему должен быть?
Если я добавил параметр, то я изменил вызываемый код.
В вызывающем коде менять ничего не нужно.
Вариант первый использование наследника базового функционала.
То есть TCallContextBase(базовый набор) и TCallContextExtended(расширенный набор), где TCallContextExtended=class(TCallContextBase) в
вызываемом коде стоит первая проверка
TCallContextBase=class
a:integer;
b:string;
end;
TCallContextExtended=class(TCallContextBase)
с:variant;
constructor create(a..,b..,c..)
end;
Вызываемая функция
function Workfunc(context:TCallContextBase):...
begin
if context is TCallContextExtended then
else
if context is TCallContextBase then
begin
//если появились какие либо обязательные параметры для старых
вызовов инициализируем их по умолчанию
end
else exit;
end;
Вызывающая функция
Workfunc(TCallContextBase.create(1,"2"))
Ничего менять не нужно для вызывающей стороны.
← →
oxffff © (2008-10-14 19:59) [46]
> Сергей М. © (14.10.08 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 20:01) [47]
> у меня вызывающий код ничего не проверяет
Дык о чем тогда базар ?)
Читай еще раз и внимательно:
> Как до вызова f определить корректность параметров?
← →
oxffff © (2008-10-14 20:15) [48]
> Дык о чем тогда базар ?)
> После того как "отцы" ресурса с какого-то бодуна взяли да
> добавили обязательный 3-й параметр при запросах к ресурсу,
> стало:
> someproto://somedomain/someresource?param1=A?param2=B?param3=C
> А я ничего не зная об этом по-прежнему запрашиваю с 2-мя
>
> параметрами.
>
> Кто ответственен за возможную коррекцию моей ошибки или
>
> корректный отлуп запроса ?
> Разумеется, сервер (вызываемый код) ! Не браузер же (вызывающий
>
> код) !
> Иначе на каждый чих "отцов" придется переписывать каждый
>
> браузер)
Да почему базар?
А у меня встречный вопрос. Вы [37] спрашивали про третий обязательный параметр. В моем способе я показал как выкрутиться для старого кода.
А в предложенном вами способе разве не придется менять код вызывающего
для дополнительного обязательного параметра. А то вы тут намекаете на негибкость предложенного мною метода, а про свой, что скажете, повторяю обязательного. В вашем же случае тоже придется менять код вызывающего.
Может он все таки не такой уж и обязательный, чтобы старый Idispatch код работал?
;)
← →
oxffff © (2008-10-14 20:19) [49]
> Читай еще раз и внимательно:
>
>
> > Как до вызова f определить корректность параметров?
В run time только TypeInfo поможет до вызова стороне клиента.
← →
oxffff © (2008-10-14 23:44) [50]Я тут слегка усовершенствовал свою версию
отцепив привязку от провайдера контекста.
TContex=record
a,b:integer;
c:string;
end;
IContextProvider=interface
["{C98B6149-BCCA-432D-B9B8-9066ACDAA253}"]
function AssignContext(var Contex:TContex):boolean;
end;
TContextProvider=class(TInterfacedObject,IContextProvider)
protected
function AssignContext(var Contex:TContex):boolean;virtual;abstract;
end;
TContextProvider1=class(TContextProvider)
protected
DataA,DataB:integer;
function AssignContext(var Contex:TContex):boolean;override;
public
constructor create(DataA,DataB:integer);
end;
TContextProvider2=class(TContextProvider)
protected
DataA:integer;
DataC:string;
function AssignContext(var Contex:TContex):boolean;override;
public
constructor create(DataA:integer;DataC:string);
end;
function WorkFunc(Unknown:IUnknown):boolean;
var Contex:TContex;
ContextProvider:IContextProvider;
begin
try
ContextProvider:=Unknown as IContextProvider;
//Устанавливаем значение по умолчанию
Contex.a:=0;
Contex.b:=0;
Contex.c:="Значение по умолчанию";
//Получаем данные контекста вызова
if ContextProvider.AssignContext(Contex) then
begin
showmessage("a="+inttostr(Contex.a)+" b="+inttostr(Contex.b)+" c="+Contex.c);
result:=true;
exit;
end;
except
end;
result:=False;
end;
{ TContextProvider1 }
function TContextProvider1.AssignContext(var Contex: TContex): boolean;
begin
Contex.a:=DataA;
Contex.b:=DataB;
end;
constructor TContextProvider1.create(DataA, DataB: integer);
begin
self.DataA:=DataA;
self.DataB:=DataB;
end;
{ TContextProvider2 }
function TContextProvider2.AssignContext(var Contex: TContex): boolean;
begin
Contex.a:=DataA;
Contex.c:=DataC;
end;
constructor TContextProvider2.create(DataA:integer;DataC:string);
begin
self.DataA:=DataA;
self.DataC:=DataC;
end;
{ TContextProvider }
procedure TForm1.Button1Click(Sender: TObject);
begin
WorkFunc(TContextProvider1.create(1,2));
WorkFunc(TContextProvider2.create(1,"Параметр задан"));
end;
← →
Сергей М. © (2008-10-15 13:10) [51]
> oxffff
Автор уже забыл свою изначальную затею как страшный сон , а ты все мысли плодишь на эту тему)
Обрати внимание - вопрос вырос из указателя.
А в [28] автор ортогонально развернул оглобли, так что от первоначальная идеи не осталось и следа.
Пилите, Шура, пилите !)
← →
oxffff © (2008-10-15 14:14) [52]
> Сергей М. © (15.10.08 13:10) [51]
Мысли рождаются сами собой.
Например [50] пришла в голову в ванной, когда я мылся после тяжелой физической работы(ремонт дома делаю). Неоднократно замечено, что физический труд очень полезно. Столько мыслей сразу.
:)
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.11.23;
Скачать: [xml.tar.bz2];
Память: 0.61 MB
Время: 0.013 c