19.06.2009, 18:40 | #1 |
Участник
|
DictEnum.index2XXXX() & DictEnum.value2XXXX()
Dynamics Ax 4.0 SP2 (application version: 4.0.2501.347), Dynamics Ax2009 (application version: 5.0.1001.176)
После темы Баг в InventItemType? из 'спортивного интереса' решил посмотреть на сколько часто в коде Ax встречаются ситуации когда разработчики использовали 'индекс' (порядковый номер) элемента перечисления в качестве его значения, либо наоборот - трактовали значение как порядковый номер элемента перечисления. По перекрестным ссылкам выборочно посмотрел где(как) используются методы классов (Sys-)DictEnum.index2Name(), (Sys-)DictEnum.index2Symbol(), (Sys-)DictEnum.value2Name(), (Sys-)DictEnum.value2Symbol() и методы SysDictEnum: firstValue(), lastValue(), nextValue(). В результате обнаружилось достаточное количество мест, код которых вызывает вопросы и претендует на рефакторинг. Приведу некоторые примеры кода на анализ которого потратил немного времени. Forms\SysRecordInfo\Methods\buildInsertScript(): X++: void buildInsertScript() { ... boolean setFieldValue(fieldId _fieldId) { ... switch (dictFieldTemp.baseType()) { ... case Types::Enum : dictEnum = new DictEnum(dictFieldTemp.enumId()); fieldValue = dictEnum.name() + '::' + dictEnum.index2Symbol(common.(_fieldId)); break; ... } ... } ... } X++: fieldValue = dictEnum.name() + '::' + dictEnum.value2Symbol(common.(_fieldId)); Цитата:
InventTable.ItemGroupId = "Электротехника";
InventTable.ItemId = "Эле_000085"; InventTable.ItemName = "Перфоратор с пылесосом, Макита"; InventTable.ItemType = ItemType::; Classes\CCPivotTable\addEnums(): X++: void addEnums(SysDictField sysDictField) { ... for (n=0; n<dictEnum.values(); n++) { OLAPEnums.EnumValue = n; OLAPEnums.EnumText = dictEnum.value2Name(n); OLAPEnums.EnumName = dictEnum.name(); OLAPEnums.Language = languageId; OLAPEnums.insert(); } ... } X++: OLAPEnums.EnumText = dictEnum.index2Name(n); Classes\SysLookup\enumLabel2Id(): X++: // return -1 when enum label does not exsist. public client server static int enumLabel2Id(enumId _enumId, LabelType _labelType) { DictEnum dictEnum = new DictEnum(_enumId); int i; ; for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(dictEnum.value2Label(i)), strltrim(_labelType))) { return i; } } for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(dictEnum.value2Name(i)), strltrim(_labelType))) { return i; } } for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(int2str(i)), strltrim(_labelType))) { return i; } } return -1; } Результат метода используется в SysLookup::lookupTableFixedRelation(): X++: private static RelationName lookupTableFixedRelation(tableId _tableId, Common _common, Set _fixedRelationSet) { ... if (relationField.enumId()) { ... if (tmpSysQuery && dictRelation.lineExternTableValue(j) == SysLookup::enumLabel2Id(relationField.enumId(), tmpSysQuery.RangeValue)) ... } ... } Для тестирования набросал небольшой job: X++: static void jbSysLookupCheck(Args _args) { void checkSysLookup_EnumLabel2Id( ItemType _itemType ) { SysDictEnum sysDictEnum = new SysDictEnum( enumNum( ItemType ) ) ; LabelType labelType ; ; setPrefix( strfmt( "%1: %2 (%3)", sysDictEnum.name(), _itemType, any2int( _itemType ) ) ) ; labelType = sysDictEnum.value2Label( _itemType ) ; info( strfmt( "by label: %1 (%2)", labelType, SysLookup::enumLabel2Id( sysDictEnum.id(), labelType ) ) ) ; labelType = sysDictEnum.value2Name( _itemType ) ; info( strfmt( "by name: %1 (%2)", labelType, SysLookup::enumLabel2Id( sysDictEnum.id(), labelType ) ) ) ; labelType = strfmt( "%1", any2int( _itemType ) ) ; info( strfmt( "by value: %1 (%2)", labelType, SysLookup::enumLabel2Id( sysDictEnum.id(), labelType ) ) ) ; } ; info( "SysLookup::enumLabel2Id()" ) ; checkSysLookup_EnumLabel2Id( ItemType::Service ) ; checkSysLookup_EnumLabel2Id( ItemType::Asset_RU ) ; } Цитата:
SysLookup::enumLabel2Id()
-ItemType: Услуга (2) --by label: Услуга (2) --by name: Услуга (2) --by value: 2 (2) -ItemType: Основные средства (100) --by label: Основные средства (-1) --by name: Основные средства (-1) --by value: 100 (-1) X++: // return -1 when enum label does not exsist. public client server static int enumLabel2Id(enumId _enumId, LabelType _labelType) { DictEnum dictEnum = new DictEnum(_enumId); int i; ; for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(dictEnum.index2Label(i)), strltrim(_labelType))) { return dictEnum.index2Value(i); } } for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(dictEnum.index2Name(i)), strltrim(_labelType))) { return dictEnum.index2Value(i); } } for (i=0; i < dictEnum.values(); i++) { if (!strcmp(strltrim(int2str(dictEnum.index2Value(i))), strltrim(_labelType))) { return dictEnum.index2Value(i); } } return -1; } Classes\smmSourceType\preDefinedType() (AX2009): X++: public static boolean preDefinedType(str _sourceType) { SysDictEnum sysDictEnum = new SysDictEnum(enumnum(SmmSourceTypeList)); int i; ; for (i = sysDictEnum.firstValue(); i <= sysDictEnum.lastValue(); i = sysDictEnum.nextValue(i)) { if (sysDictEnum.index2Value(i) != SmmSourceTypeList::UserDefined && sysDictEnum.index2Name(i) == _sourceType) { return true; } if (i == sysDictEnum.lastValue()) { break; } } return false; } imho, ожидалась проверка значения: X++: if ( i != SmmSourceTypeList::UserDefined &&
sysDictEnum.value2Name(i) == _sourceType) Для тестирования добавил в перечисление SmmSourceTypeList элемент CheckCode_Example_100, с меткой 'Example' и значением 100 и запустил job: X++: static void jbSmmSourceTypeCheck(Args _args) { void checkSmmSourceType( SmmSourceTypeList _smmSourceTypeList) { ; info( strfmt( "%1 (%2) - %3", _smmSourceTypeList, any2int( _smmSourceTypeList ), SmmSourceType::preDefinedType( strfmt( '%1', _smmSourceTypeList ) ) ) ) ; } ; setPrefix( "SmmSourceType::preDefinedType()" ) ; checkSmmSourceType( SmmSourceTypeList::Employee ) ; checkSmmSourceType( SmmSourceTypeList::CheckCode_Example_100 ) ; } Цитата:
SmmSourceType:: preDefinedType()
- Сотрудник (2) - true - Example (100) - false Пример из кода локальной функциональности, Classes\InventJournalPrintForm_RU.run(): X++: private void run() { ... DictEnum dictEnum = new DictEnum(enumnum(InventJournalReportType_RU)); ... InventJournalReport_RU report; ... while (it.more()) { ++gridCnt; report = it.value(); dsName = dictEnum.index2Symbol(report.reportType()); ... } ... while (it.more()) { report = it.value(); dsName = dictEnum.index2Symbol(report.reportType()); ... } ... } Ожидалось X++: dsName = dictEnum.value2Symbol(report.reportType()); P.S. Надеюсь члены группы Microsoft Dynamics (если они просматривают форум) обратят внимание на этот топик, по возможности прокоментируют сделанные выводы и инициируют рефакторинг прикладного кода использующего методы DictEnum.value2XXXX() и DictEnum.index2XXXX() на предмет устранения подобных накладок (скрытых багов). |
|
|
За это сообщение автора поблагодарили: mazzy (5), jeky (1). |
19.06.2009, 19:47 | #2 |
Участник
|
Рефакторинг не обещаю, но некорректные использования пофиксят, думаю.
|
|
|
За это сообщение автора поблагодарили: Logger (5). |
20.06.2009, 15:36 | #3 |
Участник
|
new DictEnum()
Dynamics Ax 4.0 SP2 (application version: 4.0.2501.347), Dynamics Ax2009 (application version: 5.0.1001.176)
Еще немного о DictEnum: использование числовых идентификаторов вместо enumNum() - тут Best Practices не помешал бы
X++: void treeImageExplain() { DictEnum dictEnum = new DictEnum(102); int counter; int imageNo; ; ctrlImageExplain.deleteAll(); ctrlImageExplain.visible(tmpReqExplosionTree.SettingsDisplayImageExplain); if (!tmpReqExplosionTree.SettingsDisplayImageExplain) return; while (counter < 40 /*enumcnt(ReqRefType)*/) { counter++; imageNo = this.displayImageReqRefType(counter); if (imageNo) { //BP Deviation documented ctrlImageExplain.addItem(new FormListItem(dictEnum.value2Name(counter),imageNo)); } } imageNo = this.displayImageReqRefType(ReqRefType::ItemPlannedOrder,true); if (imageNo) { //BP Deviation documented ctrlImageExplain.addItem(new FormListItem("@SYS9646",imageNo)); } } X++: str toolTip() { DictEnum dictEnum = new DictEnum(112); ... } \Forms\BOMConsistOf\Designs\Design\[Group:GroupBOM]\[Tab:Tab]\[TabPage:Overview]\[Grid:GridBOM]\Window:ItemTypeIcon\Methods\toolTip X++: str toolTip() { DictEnum dictEnum = new DictEnum(118); ... } \Forms\ProdCalcTrans\Designs\Design\[Tab:Tab]\[TabPage:OverviewEstimation]\[Grid:EstimationGrid]\Window:TypeEstimationGrid\Methods\toolTip X++: str toolTip() { DictEnum dictEnum = new DictEnum(112); ... } |
|
|
За это сообщение автора поблагодарили: ZVV (5). |
23.06.2009, 14:24 | #4 |
Участник
|
enumcnt() & dictEnum.value2Name() & InventItemType::construct()
Dynamics Ax 4.0 SP2 EE
Добавлю своих '5 копеек' до кучи, где 'индекс' трактуется как значение перечисления:
X++: DictEnum dictEnum = new DictEnum(enumnum(ItemType)); ... for (i=enumcnt(ItemType);i>0;i--) { inventItemType = InventItemType::construct(i-1); if (inventItemType) { imageNo = inventItemType.imageRessNo(); if (imageNo) { //BP Deviation documented imageExplain.addItem(new FormListItem(dictEnum.value2Name(i-1),imageList.image(imageNo))); } } }
__________________
Dynamics AX 4.0 SP2 |
|