|
31.05.2017, 16:03 | #1 |
Участник
|
например, вот такой проектик.
собрал на коленке по-старому пока билдится этот ритейл, блин. заодно узнал, что новая аксапта пиливать хотела на параметры menuItem, если menuItem сделать стартовым объектом. пришлось сделать класс starterJob. С другой стороны, показал, как запускать через menuItem )))) ============================== состав проекта: С starterJob и объекты суффиксом MST - новые. остальные переопределенные думаю, тем у кого нет акс7, скриншотов хватит. чтобы увидеть исходные тексты без аксапты, скачайте aa.axpp, измените расширение на .zip и посмотрите в содержимое. ============================== Disclimer: проектик безумен ровно настолько, насколько безумен исходный текст семейства классов. У нормальных людей есть нормальные обвязки для args, параметров, запускачей и прочее. но и такие безумные поделки приходится развивать-поддерживать на проектах. Последний раз редактировалось mazzy; 31.05.2017 в 16:07. |
|
|
За это сообщение автора поблагодарили: sukhanchik (4). |
31.05.2017, 20:02 | #2 |
Участник
|
Хороший проектик. Тут вопрос такой. В том что ты сделал: если задать сочетание Vend и MST это правильно что он молча это понимает и не ругается? Если допустимо, чтобы он ругался на такое сочетание. То для расширения черех SysExt надо пометить атрибутом новый класс. Типа
X++: [CustVendSettlerKey(Module::Cust, #MSTKEY)] clas MyNewSettler ... X++: class CustVendSettlerKeyAttribute extends SysAttribute implements SysExtensionIAttribute { Module module; str mode; public void new(Module _module, str _mode = '') { module = _module; mode = _mode; } public str parmCacheKey() { return [ classStr(CustVendSettlerKeyAttribute), module, mode] ; } public boolean useSingleton() { return false; } X++: SysExtensionAppClassFactory::getClassFromSysAttribute(classStr( ), new CustVendSettlerKeyAttribute(_module, _mode)); |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
01.06.2017, 19:32 | #3 |
Участник
|
Эпиграф 1:
- Перебилдь - Сам ты Перебилдь Эпиграф 2: Пока для начала ссылка на прошлый проект с традиционными construct: Цитата:
как и в прошлом проекте, я постарался сделать качественно и кратко настолько насколько это возможно. но при этом использовать только штатные средства, которые входят в текущую поставку. время на этом проекте конечно не показатель, поскольку сейчас много куда смотреть пришлось. но занимался я им 4-5 перебилдов и пару передеплоев ритейла - часа 4. следующие подобные проекты можно выполнять за те же 10-15 минут. логика поведения Аксаптовских объектов вывернута наизнанку. Например, стандартно menuItem указывает на объект. А в фреймворке наоборот, к объекту привязывается menuItem, а в menuItem указыается клаcc запускач. И так во всем фреймворке. да, я сейчас написал так, что перекрестные ссылки на все объекты есть. но и их логика вывернута. да, очень велика вероятность того, что вместо classstr, menuItemActionStr программисты будут тупо использовать простые строки и перекрестных ссылок не будет в принципе. да, всегда остается возможность поиска подстроки с названием объекта... но очень боюсь, что и они будут составными и ненаходимыми. ну, и, конечно, все ушло в рантайм. конечно, да, рантайм дает позднее связывание. но контроль на этапе компиляции - это контроль на этапе компиляции. и сообщения в рантайм "неправильное использование функции" без информации какие именно аргументы были у этой функции - это прекрасно! и вы будете ржать, то однажды выполнившись на АОС, атрибут-класс кэшируется, если код изменить неправильно (неуникальное или несуществующее значение артрибута, например) то оно будет выполнять исходя из закешированных значений атрибутов. или я полностью не понимаю происходящее. но уверен, что ЭТО прекрасно! и пока совершенно не понимаю, как ЭТО покрывать тестами. и пока не могу найти примеров в существующем коде, чтобы ЭТО было покрыто тестами. надо подумать. ============================= суть проекта: main() перенесен в отдельный класс-запускач. логика всех конструкторов размазана по атрибутам и main() в запускаче. у классов потомков проставлены атрибуты, привязанные к menuItem для всех запускаемых классов есть свой menuItem все релевантные menuItem переброшены на класс-запускач ============================= кажется, что логика запуска стала проще. но это только потому что это такая безумная реализация в данном примере - обычно никто не делает переключение логики при помощи parm в меню итеме. обычно, логика запуска класса должна быть более изощренна. следовательно, будет более запутана - часть в атрибутах, часть в коде, который готовит ключи на основании параметров, датасорсов и caller... опять же - получается совершенно вывернутая логика. раньше логика запуска была размазана по конструкторам - каждый отвечал за свой уровень в иерархии. теперь логика запуска размазана по атрибутам и одновременно сконцентрирована в main(). я пока не очень понимаю что будет если разные партнеры расширят семейство классов каждый по своему, а потом заказчик должен будет эти расширения объединить в одном main. возможно, можно как-то комбинировать стратегии. =============================== ну, и строка-ключ с позиционными данными и с разделителем ; это пипец, товарищи. =============================== на скриншотах циферки: 1. нужно указывать базовый класс 2. нужно делать cast. для этого нужно знать к какому базовому классу кастить. в семействе может быть несколько базовых с разной логикой. см FormLetter. 3. перекрестные ссылки с базового класса CustVendAutoDialog_RU - да, если писать правильно, то перекрестные ссылки есть Последний раз редактировалось mazzy; 01.06.2017 в 19:44. |
|
|
За это сообщение автора поблагодарили: ax_mct (9), sukhanchik (10), macklakov (10), Logger (3). |
01.06.2017, 20:15 | #4 |
Banned
|
Передаем параметром в new ассоциативный массив, то же Map [имя переменной - key, ее значение - value]. Учим корень типа Object это парсировать.
Альтернативно передаем ключом внешнее имя переменной, mapping держим в ИмяКласса.xml. Патентуем и подаем на Нобелевскую Премию. Снимаю шляпу. Но на лабутенах!!! |
|
01.06.2017, 09:17 | #5 |
Участник
|
на посошок в нескольких словах:
очередной абсолютно не подсахаренный уровень косвенности, который [может быть] облегчает первоначальную разработку (ответсвенный: мс) но сильно затрудняет изучение/добавление/изменение в дальнешем (ответственный: партнеры-заказчики) собственно о различии в приоритетах. |
|
01.06.2017, 22:32 | #6 |
Участник
|
> 1. нужно указывать базовый класс
> 2. нужно делать cast. для этого нужно знать к какому базовому классу кастить. Тут извиняйте, если бы были дженерики, можно было бы сделать X++: var x = SysExtensionAppClassFactory::getClassFromSysAttribute<MyBaseClass>(attribute) Кстати в данном случае надо использовать не is - он вернет null если вдруг будет не ожидаемый тип а просто обявить явно тип без var - это будет все равно что строгий каст в C# (тип в скобочках). > в семействе может быть несколько базовых с разной логикой. см FormLetter. Дык все равно ты тут одижаешь какой-то один тип - класс или интерфейс, если разные, то надо либо делать разные плагины либо дальше кастить - без этого логически никак. |
|
02.06.2017, 07:51 | #7 |
Участник
|
Спасибо за проект. Посмотрю.
ага. я тоже так подумал. но этот код скопирован из существующего в аксапте. я стремился сделать штатными средствами и максимально похожим на штатную функциональность. ) |
|
02.06.2017, 08:07 | #8 |
Участник
|
is можно использовать, но только в том случае, когда в значении может быть другой класс и это валидный кейз. После чего значение перед использованием надо обязательно проверить на null. К сожалению, это частая ошибка использовать одно вместо другого. К сожалению, в X++ нету явного строгого приведения.
|
|
03.06.2017, 07:58 | #9 |
Участник
|
как можно было бы реализовать,
если бы разработчикам поставили правильную задачу: "создать фреймворк для добавления и изменения функционала, который будет доступен пользователям" вместо нелепой задачи "создать фреймворк для добавления классов" ============================ идея очень простая:
X++: abstract class BaseClass_ReadOnly extends RunBaseBatch { protected static baseClass_ReadOnly construct(Args _args /*, SysExtensionInstantiationStrategy strategy = null*/) { var attr = new FormMenuItemFactoryAttribute(_args.menuItemType(), _args.menuItemName()); var obj = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(baseClass_ReadOnly), attr); //TODO add initialization strategy return obj; } public static void main(Args _args /*, SysExtensionInstantiationStrategy initStrategy = null */ ) { baseClass_ReadOnly obj = BaseClass_ReadOnly::construct(_args /*, initStrategy */); //TODO run strategy. Default is: if( obj && obj.Prompt() ) { obj.run(); } } } но для текущей версии фреймворка атрибут нужен. X++: [FormMenuItemFactoryAttribute(MenuItemType::Action, menuItemActionStr(myMenuItem))] class MyClass extends BaseClass_ReadOnly { public void run() { //TODO something useful } public static void main(Args _args) { MyClass obj = BaseClass_ReadOnly::constuct(_args); //TODO run strategy. Default is: if( obj && obj.Prompt() ) { obj.run(); } } } Код: <?xml version="1.0" encoding="utf-8"?> <AxMenuItemAction xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="Microsoft.Dynamics.AX.Metadata.V1"> <Name>myMenuItem</Name> <Object>myClass</Object> <ObjectType>Class</ObjectType> </AxMenuItemAction> ===================== кто-нибудь хочет проанализировать и рассказать про еще один фреймворк SysPlugin, который должен решать аналогичные задачи? лучше в отдельной ветке. |
|
03.06.2017, 22:06 | #10 |
Участник
|
Цитата:
Классы бывают не только вызываемые из непосредственно из UI, не только с методами main но и всякие другие. Использование контроля прав доступа нужно далеко не везде. (Я кстати не видел нигде ключевой атрибут по mеnuitem - тут ты ломишься в открытую дверь - если класс именно вызывается - то есть потомок runbase, и по меню айтем можно его однозначно определить, то он связывается с ним непосредственно). Последний раз редактировалось belugin; 03.06.2017 в 22:18. |
|
04.06.2017, 22:26 | #11 |
Участник
|
Цитата:
Цитата:
Сообщение от Raven Melancholic
Для начала, чтобы не тратить время, определимся что такое конструктор. На мой взгляд, конструктор это то, что создает класс. В Аксе это метод new. Принято создавать статический метод construct, но, несмотря на название это все-таки не конструктор в общем понимании, а метод фабрики.
Цитата:
Цитата:
насколько я помню, это было еще до того, как научились сохранять параметры диалога для пакетных заданий. сейчас скорее будет запущено что-то через главное меню или через меню в какой-то форуме. Цитата:
но пусть будут такими, что покрывают множество сценариев использования. пусть они будут универсальными. Цитата:
я говорю о добавлении функционала, который потом будет предоставлен пользователям. чтобы предоставить пользователям добавленный класс, нужен будет menuItem. Цитата:
Сообщение от belugin
Классы бывают не только вызываемые из непосредственно из UI, не только с методами main но и всякие другие. Использование контроля прав доступа нужно далеко не везде. (Я кстати не видел нигде ключевой атрибут по mеnuitem - тут ты ломишься в открытую дверь - если класс именно вызывается - то есть потомок runbase, и по меню айтем можно его однозначно определить, то он связывается с ним непосредственно).
не нужен UI - просто создай menuItem и ничего с ним не делай. понадобиться - просто продолжай использовать menuItem. в отличие от атрибута. вы снова говорите как это работает. это работает. я говорю о трудоемкости и стоимости работ на разобраться, добавить функционал, дать пользователю, поддерживать в дальнейшем. технология на атрибутах требует двойных-тройных трудозатрат. я только об этом. и да: большинство преимуществ атрибутов можно проявить только для решения внутренних МСовских задач и только в окружении МС, где атрибуты уже повсеместно используются. Там таки да - шикардос и позднее связывание рулит. остальным только усложнит жизнь. Последний раз редактировалось mazzy; 04.06.2017 в 22:41. |
|
04.06.2017, 23:06 | #12 |
Участник
|
чтобы не быть голословным.
по существующей технологии - для того, чтобы помечать атрибутом, нужно создать класс атрибута и прописать как параметры будут преобразованы в ключ. всего сейчас 83 потомка от SysExtensionAttribute. 3 из них универсальные - enum, menuItem, dataset. остальные - как правило просто специализированные классы для enum'ов. (почему не универсальный FormEnumSymbolFactoryAttribute? а ХЗ. универсальный класс сейчас используется только в 8 местах) так вот, получается, чтобы работать по текущим рекомендациям с атрибутами, нужно: = создать сам класс и встроить его в иерархию = разобраться с классом атрибутов и встроить туда (или создать класс атрибутов) = разобраться с фабрикой и встроить туда = добавить menuItem, если нужно дать функционал пользователю, разобраться как menuItem должен запустить нужный класс плюс работа, которой никогда нет в МС, но частенько бывает на проекте - решить что делать с функционалом, который добавлен разными партенрами. раньше пересечения нужно было искать только в construct. теперь пересечения нужно искать по разнообразным семействам - классы, атрибуты, стратегии инстанцирования, menuItem. |
|
03.06.2017, 08:55 | #13 |
Участник
|
Спасибо добрым людям, которые подсказывают, что:
Если уж так хочется сделать фреймворк, то скомбинировали бы два существующих класса. Если уж так хочется заменить makeObject на .net инстанцирование, которое "в 4 раза быстрее", то изменили бы код в существующих классах. А всего то разница в постановке задачи. МС-разработчикам сказали сделать добавление классов, но не сказали как это будет использоваться. Они и сделали ТОЛЬКО добавление классов. Эх... Последний раз редактировалось mazzy; 03.06.2017 в 09:18. |
|
03.06.2017, 21:26 | #14 |
Участник
|
Теперь вернемся к методу construct.
Я то же не понимаю, почему для какого-то метода фабрики класса есть ограничения в BP. То есть, если я хочу фабрику назвать construct, то должен следовать BP и делать его без параметров, а если хочу назвать make, то могу делать что угодно (название create не рассматриваем, оно без предупреждения в каких-либо описаниях используется для распаковки). Опять же ответ в том, как стандартное приложение ожидает в некоторых местах наличие и следование определенным правилам методов. Сам лично не сталкивался в реальной работе с проблемой (в отличие от метода new с параметрами) construct с параметрами, но видел ,что есть места, в которых в стандартном приложении есть вызова статического метода construct ожидающие, что он без параметров. |
|
03.06.2017, 21:38 | #15 |
Участник
|
Цитата:
Я говорю именно о месте, где производится инициализация объекта нового класса.
Например, мы сказали в своем case, что создать Наследник::make(нечто). Когда писали вызов создания этот наследник был именно "Наследник", но впоследствии разработчик "Наследника" решил что он слишком много на себя берет и разбил его на несколько классов со своей структурой наследования, а в make написал что-то, что в зависимости от состава "нечто" создает нужного наследника. То есть, в своем классе мы не можем предполагать, что же именно будет создано. Мы можем только надеяться, что поведение будет нужным нам. Кстати, не вижу разницы, будет ли фабрика при создании классов опираться на switch-case или аттрибуты. |
|
03.06.2017, 21:58 | #16 |
Участник
|
Понимаю, что mazzy ждет от поведения системы (то же что и другие люди, знакомые в Аксой, в том числе и я): привычные подходы, которые используются кучу лет, простые способы внесения изменений, ловлю любых зависимостей перекрестными ссылками и т.п. Оставим пока слухи о том, что, не исключено, что могут вообще быть закрыты некоторые способы изменений.
Я не очень понимаю, почему mazzy считает, что изменение иерархии путем включения какого-то класса не в качестве последнего листа, а в середину иерархии отличается при использовании фабрики, основанной на атрибутах и фабрики, основанной на switsh-case? Один фиг в обоих случаях придется искать все объявления переменных класса, который был раньше непосредственным наследником, а теперь переместился по иерархии выше, чем был ранее. |
|
08.06.2017, 15:52 | #17 |
Banned
|
А можно поинтересоваться, как вы создаете окружность по двум точкам? : )
|
|
08.06.2017, 16:37 | #18 |
Участник
|
|
|
08.06.2017, 17:54 | #19 |
Участник
|
или окружность бесконечного радиуса, проходящая через заданные точки.
|
|
11.06.2017, 00:58 | #20 |
Banned
|
Brian decides a magic climbing fork is the best way to climb into the tower to retrieve the amulet and get home.
https://www.youtube.com/watch?v=44IgPvJJpa0 |
|
Теги |
sysextension framework, sysoperation framework, как правильно, полезное |
|
|