18.01.2008, 11:06 | #1 |
Участник
|
Передача функции в качестве параметра
Всем доброго времени суток, подскажите пожалуйста возможна ли передача функции в другую функцию в качестве параметра?
|
|
18.01.2008, 11:22 | #2 |
Moderator
|
А.... еще один поклонник фунционального программирования?
А что есть в Аксапте функция? В метод класса можно передать объект, а в самом методе вызвать его метод (то бишь функцию), если я вас правильно понял. |
|
18.01.2008, 11:35 | #3 |
Banned
|
Можно передать объект и название функции строкой. Вызвать метод через DictClass.
|
|
18.01.2008, 11:42 | #4 |
Участник
|
Да, спасибо именно так и сделал
|
|
18.01.2008, 13:48 | #5 |
Участник
|
Цитата:
Аксапта - объектно-ориентированная система. в ООП не передают функции. в ООП создают семейство классов, в наследниках указывают функции и передают объект нужного типа. кроме всего прочего, за счет этого осуществляется дополнительный контроль типов. поэтому напишите обертку над вашими функциями. пример - класс SysFileDeployment и его наследники, которые переопределяют функцию filename |
|
18.01.2008, 13:49 | #6 |
Участник
|
Цитата:
сделать так конечно можно. но я бы расстрелял исполнителя, который выбрал бы на моем проекте такую реализацию в Аксапте. |
|
18.01.2008, 20:18 | #7 |
Участник
|
Маззи, у нас сделана доработка в документообороте, что можно использовать и Дисплей-методы
Если подан параметр правильно, то никаких проблем - methodStr и тому подобные |
|
18.01.2008, 20:25 | #8 |
Участник
|
Цитата:
как скажете. |
|
18.01.2008, 20:26 | #9 |
Banned
|
|
|
18.01.2008, 22:23 | #10 |
Участник
|
Расскажите подробнее, что за доработка, и какую цель преследует, будьте так любезны.
Последний раз редактировалось kashperuk; 18.01.2008 в 22:24. Причина: описался :) |
|
19.01.2008, 01:12 | #11 |
Участник
|
>>>в ООП не передают функции.
Самый что ни на есть объектно ориентированный смолток, например, вообще не содержит управляющих конструкций. Вместо них есть методы, которым передают блоки The Smalltalk Language X++: "Prints the integers between 1 and 10, and a string stating whether each is even or odd" 1 to: 10 do: [:n | n even ifTrue: [ Transcript show: n; show: ' is even'; cr] ifFalse: [ Transcript show: n; show: ' is odd'; cr] ] 1 to: 10 do: <блок> to:do: - это сообщение которое посылается объекту "число единица" с параметрами 10 и блоком (по сути дела анонимной функцией) В обзщем в чистых объектноориентированнх языках все есть объект и даже функции это объекты, которые могут передаваться в качестве параметров, храниться в коллекциях и прочее. Но в целом, я согласен с Маззи, что в X++ это выглядит настолько криво, что надо сильно взвещивать количество геморроя, использовать всяческие intristic functions типа methodStr или покрывать использоваение тестами. Еще стоит напомнить, что есть такая вещь как интерфейсы, а рантайм при вызове методов типы классов не проверяет, а просто иет методы по имени. То есть интерфейсы можно использовать для декларации вызова функционала, при этом не обязательно декларировать то, что класс имплементит этот функционал (им это даже может быть не класс, а недокласс, например, форма). То есть реально рантайм поддерживает "утиную типизацию" хотя на уровне проверки при компиляции и IDE поддерживается манифестная статическая типизация. Этим можно пользоваться и пользуются. |
|
19.01.2008, 10:55 | #12 |
Участник
|
Цитата:
Кстати, проверка в runtime, на наличие у класса функции с определенным именем есть (также как и для таблицы и, по-моему для формы), так что при граммотном написании кода, никаких проблемм не вижу. Последний раз редактировалось petr; 19.01.2008 в 14:46. Причина: Ошибки |
|
19.01.2008, 12:33 | #13 |
Участник
|
|
|
19.01.2008, 15:27 | #14 |
Участник
|
Код метода RunBase::getDescription
X++: /*MAN Returns a helptext of the class with the specified classId. */ client server static HelpTxt getHelpText(classId _classNum) { ExecutePermission casPerm = new ExecutePermission(); SysDictClass classObj; str staticName = identifierstr(helpText); // *** if (! _classNum) return ''; classObj = new SysDictClass(_classNum); if (classObj.hasStaticMethod(staticName)) { casPerm.assert(); //BP Deviation Documented return classObj.callStatic(staticName); } else return ''; } X++: /*MAN Returns a helptext of the class with the specified classId. */ client server static HelpTxt getHelpText(classId _classNum) { ExecutePermission casPerm = new ExecutePermission(); SysDictClass classObj; str staticName = identifierstr(helpText); // *** if (! _classNum) return ''; classObj = new SysDictClass(_classNum); if (classObj.hasStaticMethod(staticName)) { casPerm.assert(); //BP Deviation Documented return classObj.callStatic(staticName); } else return ''; } А если таких методов будет сотня. Копировать все код сотню раз? Не лучше ли написать одну функцию наподобие такой: X++: client server static AnyType getProperty(classId _classNum, SysMethodName _methodName) { ExecutePermission casPerm = new ExecutePermission(); SysDictClass classObj; if (! _classNum) return ''; classObj = new SysDictClass(_classNum); if (classObj.hasStaticMethod(_methodName)) { casPerm.assert(); //BP Deviation Documented return classObj.callStatic(_methodName); } else return ''; } X++: RunBase::getProperty(classidget(this), identifierstr(helpText)); |
|
19.01.2008, 17:40 | #15 |
Участник
|
в принципе это не очень хорошо - такой вызов статических методов. Например, эти самые дескрипшены не наследуются. Здесь вполне можно было сделать без статика.
X++: ClassDescription description() { } |
|
19.01.2008, 18:52 | #16 |
Участник
|
Ну, я может не самый удачный пример привел. Просто хотел показать, что конструкция:
X++: classObj = new SysDictClass(_classNum); if (classObj && classObj.hasStaticMethod(staticName)) { casPerm.assert(); //BP Deviation Documented return classObj.callStatic(staticName); } X++: classObj = new SysDictClass(_classNum); object = classObj.makeObject(); if (classObj && classObj.hasObjectMethod(objectName)) { casPerm.assert(); //BP Deviation Documented return classObj.callObject(objectName, object); } И во втором случае, как раз и получается передача функции (в нашем случае ее имени) как параметр. Вообще, в своей практике использовал только вызов по имени метода таблицы, т.к. от этого уж точно никуда не деться, пример выше привел Delfins. Цитата:
Если наследник по сути делает тоже самое, что и родитель (только немного иначе), у него метод main я и не перекрываю, просто в construct родителя инициализирую класс наследника. Если же наследник делает что-то другое, то и menuitem другая, и в наследнике свой main и я не считаю, что в данном случае это будет дублированием. |
|
|
За это сообщение автора поблагодарили: alex55 (1). |
19.01.2008, 21:09 | #17 |
Участник
|
И еще насчет description
То, что этот метод статический, удобно использовать при проверке входных условий при вызове класса в main. Если какое-либо условие не выполняется, то можно вывести сообщение об ошибке без инициализации класса (которая невозможна при неправильных входных данных), т.е. не надо копировать метку из description в сообщение об ошибке, а просто написать что-то подобное: X++: public static void main(Args args) { MyClass myClass1; ; if (! args.record()) throw error(Error::missingRecord(MyClass::description())); // etc... } |
|
21.01.2008, 07:50 | #18 |
Участник
|
Цитата:
Цитата:
Во-первых, это пример не передачи "функции", а вызова совершенно конретной для разных классов. Во-вторых, продолжаю настаивать, что вместо "передачи функции" более правильным способом является создание семейства классов, в каждом из наследников которого имеется своя реализация "функции", а затем передавать объект и вызывать эту реализацию. В-третьих, готов согласиться, что в некоторых случаях создание и поддержка подобного семейства является более трудоемким нежели грамотные проверки до вызова. Но число таких случаев сильно ограничено. И каждый случай должен быть хорошо обоснован программистом. В большинстве случаев не надо передавать методы. В большинстве случаев надо создавать семейства классов (пример SysFileDeployer, axdBase, ImageListAppl, LedgerBalance и т.п.) В стандартной ax4.0 sp2 имеется всего 128 случаев работы с методами напрямую. многие из этих случаев являются антипаттернами (показывают как НЕ надо делать) Код: Class SysDictClass.hasObjectMethod \Data Dictionary\Tables\AifPipelineComponent\Methods\description \Classes\SysDictClass\hasObjectMethod \Classes\AxInternalBase\setParmMethodAsNotMandatory \Classes\AxdBase\setParmMethodAsMandatory \Classes\BatchJournalRun\canClassGoBatchJournal \Classes\SysBPCheckMemberFunction\checkUseOfCASProtectedAPIs \Classes\SysLabelFind\controlName2Id \Classes\SysTest\hasMethod \Forms\AifPipelineComponent\Data Sources\AifPipelineComponent\Methods\active \Forms\AifPipelineComponent\Methods\generateComponentLookupTable \Forms\SysRecordTemplateTable\Methods\disableIfButton \Forms\SysRecordTemplateTable\Methods\disableIfHasDataMethod Class SysDictClass.hasStaticMethod \Classes\RunBase\getDescription \Classes\SysDictClass\hasStaticMethod \Classes\RunBase\getHelpText \Classes\SysBPCheckClassNode\checkConstructors \Forms\SysClassWizard\Methods\frameworkSetDescription class SysMethodInfo \Classes\SysDictClass\hasObjectMethod \Classes\Global\tableHasInstanceMethod \Classes\Global\tableHasStaticMethod \Classes\SysDictClass\hasStaticMethod \Classes\RunBaseReport\initReportRun \Classes\SysMethodInfo\path \Classes\AxdBaseCreate\insertInPropertyInfoMap \Classes\AxdBaseGenerateXSD\addClassProperties \Classes\AxdBaseGenerateXSD\addDocumentProperties \Classes\AxdBaseRead\buildMethodInfoMap \Classes\WebLet\getDescription \Classes\WebLet\getHelpText \Classes\WebLet\inContext \Classes\WebLet\isEnabled \Classes\ProjListProjTransLayout\setNoOfDecimals \Classes\SysApplicationObjectPathInfo\methodInfo \Classes\xUtilElements\runMode \Classes\SysBPCheckClassNode\checkAbstract \Classes\SysBPCheckClassNode\checkConstructors \Classes\SysBPCheckClassNode\verifyConstructMethod \Classes\SysMethodInfo\getSource \Classes\SysBPCheckFormEditControl\checkLabelUse \Classes\SysBPCheckMemberFunction\check \Classes\SysBPCheckMemberFunction\checkSource \Classes\SysBPCheckMemberFunction\checkAccessSpecifier \Classes\SysBPCheckMemberFunction\checkVariables \Classes\SysMethodInfo\superMethodInfo \Classes\SysMethodInfo\subMethodInfoList \Classes\SysBPCheckMemberFunction\checkAOS \Classes\SysMethodInfo\runMode \Classes\SysBPCheckMemberFunction\initTmpxRefReferences \Classes\SysBPCheckMemberFunction\classDeclaration \Classes\SysBPCheckMemberFunction\checkHelpUse \Classes\SysBPCheckMemberFunction\checkLabelUse \Classes\SysBPCheckMemberFunction\checkUsed \Classes\SysBPCheckMemberFunction\checkUsedMemberFunction \Classes\SysBPCheckMemberFunction\checkUsedMemberFunctionServer \Classes\SysBPCheckMemberFunction\pseuduUtilElements \Classes\SysBPCheckMemberFunction\checkVariablesUse \Classes\SysBPCheckMemberFunction\dispose \Classes\SysBPCheckMemberFunction\init \Classes\SysBPCheckReportControl\checkGeneral \Classes\SysBPCheckReportControl\checkLabelUse \Classes\SysFormBuildDataSource\getMethodInfo \Classes\SysLabelFind\doFormEditControl \Classes\SysMethodInfo\superMethodNode \Classes\SysMethodInfo\toString \Classes\SysSecurity\getFormDisplayMethods \Classes\SysTreenodeWashClassNode\checkConstructors \Classes\xUtilIdElements\runMode Class DictMethod \Classes\smmSalesManagementQueries\allowedMethods \Classes\RunBase\checkCloseDialog \Classes\AifServiceableMethodValidator\validateMethodSignature \Classes\AifServiceableMethodValidator\hasMethod \Classes\AifServiceableMethodValidator\hasPublicAccess \Classes\AifServiceableMethodValidator\hasValidParameters \Classes\AifServiceableMethodValidator\hasValidReturnType \Classes\AifServiceableMethodValidator\validateReceiveDocument \Classes\AifServiceableMethodValidator\validateReceiveDocumentList \Classes\AifServiceableMethodValidator\validateSendDocument \Classes\AifServiceableMethodValidator\validateSendDocumentList \Classes\AifServiceableMethodValidator\validateQueryDocuments \Classes\AifServiceableMethodValidator\validateQueryEntityKeys \Classes\AifServiceableMethodValidator\validateProcessEntity \Classes\AifServiceableMethodValidator\validateProcessEntityList \Classes\AifWebMethodGenerator\getWebMethodParameterTypes \Classes\EditorScripts\getApplicableScripts \Classes\EditorScripts\showScripts \Classes\LedgerGDPdUDataExport\findSMethodBaseType \Classes\LedgerGDPdUDataExport\findSNumOfDecimals \Classes\LedgerGDPdUDataExport\findMethodBaseType \Classes\LedgerGDPdUDataExport\findNumOfDecimals \Classes\LedgerGDPdUFieldWizard\fillMethodNameList \Classes\SysDictClass\invokeObjectMethod \Classes\SysApplCheck\checkTableFieldPnameMustBeUnique \Classes\SysApplCheck\checkTreeNodeNameConflicts \Classes\SysApplCheck\showTableMethodsRunOn \Classes\SysAutoRun\execRun \Classes\SysBPCheckClassNode\checkRunBaseImplementation \Classes\SysBPCheckFormEditControl\checkReference \Classes\SysBPCheckMemberFunction\checkDiscontinuation \Classes\SysBPCheckTable\checkFieldPnameUniqueness \Classes\SysClassWizard\createAbstractMethods \Classes\SysCodeCoverage\postUpdate \Classes\SysDictClass\isInheritedVariable \Classes\SysExcelTemplateField\type \Classes\SysExcelTemplateField\extendedTypeId \Classes\SysExcelTemplateField\help \Classes\SysExcelTemplateField\label \Classes\SysHelpBookDocumentationDeveloper\genApplClassMethodHelp \Classes\SysHelpBookDocumentationDeveloper\genApplTableMethodHelp \Classes\SysHelpBookDocumentationSystem\methodSyntax \Classes\SysHelpBookDocumentationDeveloper\genParmMethodHelp \Classes\SysHelpBookDocumentationDeveloper\genConstructMethodHelp \Classes\SysHelpBookDocumentationDeveloper\processLabels \Classes\SysHelpBookDocumentationSystem\actualDictMethod \Classes\SysHelpBookDocumentationSystem\genClassMethodHelp \Classes\SysHelpBookDocumentationSystem\processLabels \Classes\SysHelpClassMethodWebLet\designView \Classes\SysMethodInfo\classDeclaration \Classes\SysTestCase\testMethods \Classes\SysUmlObjectModel\reverseEngineerClassProperties \Classes\SysUmlObjectModel\reverseEngineerMethod \Classes\SysUmlObjectModel\reverseEngineerParameters \Classes\SysUmlObjectModel\reverseEngineerTableProperties \Classes\WebReportGraph\makeTitle |
|
21.01.2008, 11:27 | #19 |
Banned
|
Цитата:
Действительно, модель данных DAX достаточно денормализованная, и связи порой не только 1:1, чтобы обойтись простыми джойнами справа. Иногда нужна еще и логика посложнее, чем "выводить всегда то, что есть в поле". Если хотите, приведу код. Особым секретом он не является, более того, мне такое даже и не хочется держать в вертикальном решении. При этом ошибок времени исполнения (см. mazzy) в таком случае возникать не может, поскольку сигнатура у всех display-методов одинаковая, и проверить наличие метода тоже труда не составляет. |
|
21.01.2008, 22:24 | #20 |
Участник
|
Цитата:
Сообщение от petr
То, что этот метод статический, удобно использовать при проверке входных условий при вызове класса в main. Если какое-либо условие не выполняется, то можно вывести сообщение об ошибке без инициализации класса (которая невозможна при неправильных входных данных), т.е. не надо копировать метку из description в сообщение об ошибке
Хотя в стандарте туда часто передают funcname(), но мне кажется, что MyClass::description() в данном случае информативнее. А создавать для этого исключения специально отдельную метку лениво. |
|