|
05.08.2015, 15:54 | #1 |
Участник
|
Ax2012. Типы операндов не совместимы с оператором
Использование функций при вычислении значений тринарных операторов в Ax2012 R3 в процессе компиляции выдает предупреждение:
Типы операндов не совместимы с оператором Как это можно вылечить, оставаясь в рамках тринарных операторов? X++: static void test(Args _args) { Qty qty; Qty qty2; ; qty = true ? qty2 : 0.0; // Нет предупреждений qty = true ? min(qty2,qty) : 0.0; // предупреждение qty = true ? 0.0 : min(qty2,qty); // предупреждение }
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
05.08.2015, 16:12 | #2 |
Участник
|
Не пробовал, но как насчет "any2real(min(qty2,qty)"?
|
|
|
За это сообщение автора поблагодарили: Владимир Максимов (5). |
05.08.2015, 16:17 | #3 |
Участник
|
Вот ведь... Действительно, приведение типов у функции min() помогло. Спасибо...
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
05.08.2015, 16:45 | #4 |
Участник
|
А как быть в случае табличных переменных и map? any2record() вроде бы нет?
X++: CustVendTable = true ? VendTable::find(...) : CustTable::find(...);
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
05.08.2015, 17:48 | #5 |
Участник
|
На последний вопрос сам спросил - сам ответил Нужно использовать метод data() соответствующей табличной переменной или MAP.
X++: CustVendTable = true ? CustVendTable.data(VendTable::find(...)) : CustVendTable.data(CustTable::find(...)); X++: // перебор записей в DataSource формы for (lookupJournalTable = (dataSource && dataSource.getFirst(1) ? journalTable.data(dataSource.getFirst(1)) : journalTable); lookupJournalTable; lookupJournalTable = (dataSource ? dataSource.getNext() : null)) { ... } Тут следует заметить, что явное преобразование типов требуется только в том случае, если вычисляемые типы тринарного оператора имеют разное значение. Например, вот такой код будет откомпилирован без ошибок. X++: CustVendTable = true ? VendTable::find(...) : VendTable::find(...);
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: Ruff (2), S.Kuskov (2). |
20.12.2020, 22:39 | #6 |
Участник
|
Цитата:
Так как при таком способе 1. теряется курсор к БД, а он бывает нужен. 2. теряется orig значение буфера. 3. buffer.data() глючно возвращает дубликат если buffer наследуемая табличка - не все поля заполняет. Возможно и при передаче буфера по ссылке внутрь вызова Data() тоже может быть фигня. см. тему Приведение типов для таблиц ax2012 (там описана проблема для orig() но у data() те же проблемы) в общем мне кажется что метод any2common_MRC() безопаснее и удобнее. Если нужно тип явно сохранить то можно задействовать SysDictTable::as вместо global::any2common_MRC Приведение типов для таблиц ax2012 Последний раз редактировалось Logger; 20.12.2020 в 22:48. |
|
21.12.2020, 04:18 | #7 |
Участник
|
Цитата:
https://ru.wikipedia.org/wiki/%D0%9A...D%D0%B8%D0%B5) в java изначально типы ковариантны. и дополнительно было очень много послаблений в примитивных типах. в аксапте изначально добавили ковариантность в методы классов. что позволяло до ax2009 указывать производные типы методах классов наследников (уж не знаю по недосмотру или был какой замысел). в ax2012 с какого-то перепуга разработчики сделали типы инвариантными как в C# 2.0. причем очень жестко. из-за этого нельзя уточнять тип в параметрах методов и в возвращаемых значениях. в качестве побочного эффекта получили вот такие затыки в тренарных операторах, а также в map (который AOT). именно из-за этого лично я считаю ax2012 худшей аксаптой изо всех сделанных. были слухи, что в ax2012 делали перегрузку методов и генерики. но ни перегрузки, ни генериков в аксапту так и не завезли. осталась только возможность писать в коде генерик типы .net (аксаптовские типа в таких конструкциях писать нельзя) System.Array<System.Object> arr; но зато в ax2012 ввели оператор языка is и as. в d365fo, насколько я помню, типы снова стали ковариантными. после того, как в C# 4.0+ добавили ковариантность для генериков это фича. Цитата:
if - это инструкция (statement), которая состоит из нескольких выражений тренарный - это одно выражение (expression) сделано "как в c#" людьми, которые кроме c# ничего не знают. если сформулировать утверждение полностью, то сразу станет понятно. достаточно дописать версию "из-за проблем с маршаллингом X++ <---> .net 3.5-" Цитата:
и не надо использовать эти угрёбищные суффиксы! пожалуйста. Цитата:
Христа ради! Цитата:
4. странные и мигающие глюки с map'ами Господи! Только не в global... там и так уже насрато... Последний раз редактировалось mazzy; 21.12.2020 в 04:54. |
|
|
За это сообщение автора поблагодарили: Logger (5). |
23.12.2020, 14:34 | #8 |
Участник
|
Цитата:
Я даже в .net framework не нашёл такую generic-конструкцию для System.Array
__________________
Дмитрий |
|
23.12.2020, 16:58 | #9 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: Logger (3). |
23.12.2020, 23:09 | #10 |
Участник
|
Гуглим:
Ковариа́нтность и контравариа́нтность[1] в программировании — способы переноса наследования типов на производные[2] от них типы — контейнеры, обобщённые типы, делегаты и т. п. Термины произошли от аналогичных понятий теории категорий «ковариантный» и «контравариантный функтор». Цитата:
Цитата:
Вот хочется проверить. У кого под руками есть 2012, можете проверить, что поддерживается именно ковариантность а не произвольное переопределение. Т.е. что контроллируется что метод производного класса обязан возвращать именно подкласс результата переопределенного метода, а не вообще все, что угодно, лишь бы оно было классом (назовем это пофиг-вариантностью) Цитата:
в ax2012 с какого-то перепуга разработчики сделали типы инвариантными как в C# 2.0. причем очень жестко.
из-за этого нельзя уточнять тип в параметрах методов и в возвращаемых значениях. X++ изначально это статически типизированный язык натянутый на не очень строго типизированный рантайм. MyClass x = otherValue; x.myMethod(a); Будет работать всегда, когда у otherValue есть метод совпадающий по имени и имеющий один обязательный параметр. Не важно, otherValue наследуется от MyClass или нет. JFYI, Параметры методов, наоборот, должны быть контровариантными см. LSP. Цитата:
были слухи, что в ax2012 делали перегрузку методов и генерики.
но ни перегрузки, ни генериков в аксапту так и не завезли. На уровне IL опциональные параметры компилируются в перегрузки. Цитата:
в d365fo, насколько я помню, типы снова стали ковариантными.
после того, как в C# 4.0+ добавили ковариантность для генериков Цитата:
сделано "как в c#" людьми, которые кроме c# ничего не знают.
Последний раз редактировалось belugin; 23.12.2020 в 23:21. |
|
28.12.2020, 14:12 | #11 |
Участник
|
Цитата:
проверил. не работает. был же сарайчик... значит, я путаю. Цитата:
их ввели где-то в 6ой версии. ввели сразу ковариантные. Цитата:
Цитата:
конечно. это всего лишь мое личное мнение. |
|
20.01.2021, 17:38 | #12 |
Участник
|
Цитата:
Сообщение от mazzy
гуглить в сторону "ковариантность" и "инвариантность".
https://ru.wikipedia.org/wiki/%D0%9A...D%D0%B8%D0%B5) в java изначально типы ковариантны. и дополнительно было очень много послаблений в примитивных типах. в аксапте изначально добавили ковариантность в методы классов. что позволяло до ax2009 указывать производные типы методах классов наследников (уж не знаю по недосмотру или был какой замысел). в ax2012 с какого-то перепуга разработчики сделали типы инвариантными как в C# 2.0. причем очень жестко. из-за этого нельзя уточнять тип в параметрах методов и в возвращаемых значениях. в качестве побочного эффекта получили вот такие затыки в тренарных операторах, а также в map (который AOT). Оставлю тут https://docs.microsoft.com/en-us/arc...the-x-language X++: Forthcoming changes to the X++ language https://docs.microsoft.com/en-us/arc...namics-ax-2012 |
|
20.12.2020, 22:08 | #13 |
Участник
|
up-ну тему.
Стали причесывать код. Там где раньше все нормально было, на тернарных операторах стало выдавать "operand types are not compatible with the operator" или "Типы операндов не совместимы с оператором." Достает. Можно как-то это убрать ? Погуглил Преобразование System.String в str https://community.dynamics.com/ax/f/...patible/577041 https://community2.dynamics-int.com/...tor-in-ax-2012 http://www.javaear.com/question/28894455.html Ясности не добавило. Мне кажется это явно какой-то баг компилятора. Так как аналогичный код написаный через if и оператор присваивания работает хорошо и ругани нет. Для примера вот такой код из реального проекта X++: public static boolean validateField_MRC(Common _record, FieldId _fieldId, boolean _ignoreDataSourceLevel = false) { DictField dictField; FormDataSource fds; FormDataObject fdo; str testStr; container con; boolean ret; ; dictField = new DictField(_record.TableId, _fieldId); fds = null; // не ругается fds = !_ignoreDataSourceLevel ? (SysDictClass::as(_record.dataSource(), classNum(FormObjectSet))) : null; // не ругается fds = !_ignoreDataSourceLevel ? (SysDictClass::as(_record.dataSource(), classNum(Object))) : null; // не ругается fds = !_ignoreDataSourceLevel ? _record.dataSource() : null; // ругается fdo = fds ? fds.object(_fieldId) : null; ret = !(dictField.mandatory() || (fdo && fdo.mandatory())) || validateFieldIsSet_MRC(_record, _fieldId); if (ret) { ret = fdo ? fdo.validate() : _record.validateField(_fieldId); // ругается - один boolean отличается от другого ? ret = fdo ? fdo.validate() : any2int(_record.validateField(_fieldId)); // не ругается ret = fdo ? fdo.validate() : any2enum(_record.validateField(_fieldId)); // не ругается ret = fdo.validate(); // не ругается ret = _record.validateField(_fieldId); // не ругается } testStr = conPeek(con, 1) ? conPeek(con, 2) : @""; // ругается testStr = conPeek(con, 2); // не ругается testStr = @""; // не ругается return ret; } 2. Какие идеи почему так сделано ? Мне пока кажется что это из-за проблем с маршаллингом X++ <---> CIL Самый простой способ, какой нашел - юзать any2XXX() функции - так читаемость кода страдает меньше всего. Либо переделывать на if else c явным присваиванием. Для случая классов и таблиц можно написать в Global свои методы any2Object_MRC() и any2Common_MRC(). Можно также задействовать SysDictClass::as() X++: // см. также Global::asObject() static public Object any2Object_MRC(anytype _parm) { Object ret; ; switch (typeOf(_parm)) { case Types::Class: // info(" any2Object_MRC:Class"); return _parm; // break; case 44: // typeOf(null) // info(" any2Object_MRC:null of Class"); return _parm; // break; case Types::AnyType: // такое бывает когда дефолтное значение anyType приходит в CIL // info(" any2Object_MRC:anyType"); return _parm; // break; default: // info(" any2Object_MRC:other"); } return ret; } X++: // см. также Global::asCommon() // и SysDictTable::as() // static public Common any2Common_MRC(anyType _parm) { ; return _parm; } Последний раз редактировалось Logger; 20.12.2020 в 22:19. |
|
20.12.2020, 22:26 | #14 |
Участник
|
Добавлю еще 3-й вопрос.
почему такой код X++: fds = !_ignoreDataSourceLevel ? _record.dataSource() : null; // ругается X++: fds = null; // не ругается X++: ret = fdo ? fdo.validate() : _record.validateField(_fieldId); // ругается - один boolean отличается от другого ? а вот так нормально X++: ret = fdo ? fdo.validate() : any2int(_record.validateField(_fieldId)); // не ругается ret = fdo ? fdo.validate() : any2enum(_record.validateField(_fieldId)); // не ругается Последний раз редактировалось Logger; 20.12.2020 в 22:50. |
|
20.12.2020, 22:31 | #15 |
Участник
|
4-й вопрос. - Кто как обходит такое поведение компилятора?
пока вижу такие способы а. Отказаться от тернарного оператора в случае когда выдает ругань. б. Использовать any2XXX функции, дописав недостающие самим в global классе. Есть ли в этом какой то риск в случае CIL ? в. Забить на предупреждения компилятора (а как их тогда подавить корректно ? Грубые хаки в виде кода на insert / write методах таблицы TmpCompilerOutput c запретом вставки записи - я не считаю. Это крайний вариант) г. ... 5-й вопрос - как с этим обстоит дело в 365-й ? Последний раз редактировалось Logger; 20.12.2020 в 22:51. |
|
30.08.2023, 16:27 | #16 |
Участник
|
Цитата:
Сообщение от Logger
4-й вопрос. - Кто как обходит такое поведение компилятора?
пока вижу такие способы а. Отказаться от тернарного оператора в случае когда выдает ругань. б. Использовать any2XXX функции, дописав недостающие самим в global классе. Есть ли в этом какой то риск в случае CIL ? в. Забить на предупреждения компилятора (а как их тогда подавить корректно ? Грубые хаки в виде кода на insert / write методах таблицы TmpCompilerOutput c запретом вставки записи - я не считаю. Это крайний вариант) г. ... сделать в Global метод X++: public static anytype tern(boolean _useFirst, anytype _parmFirstValue, anytype _parmSecondValue) { ; if (_useFirst) { return _parmFirstValue; } return _parmSecondValue; } Такой ли уж это г. способ ? |
|
30.08.2023, 17:33 | #17 |
Участник
|
Забить на Микрософт.
Также как Микрософт забил на нас. |
|
30.08.2023, 17:34 | #18 |
Участник
|
|
|
30.08.2023, 17:47 | #19 |
Участник
|
У варианта "г" будет особенность, что оба выражения будут вычисляться (выполняться) в любом случае, в отличие от тернарного оператора.
Помимо оптимизации это не всегда допустимо. |
|
|
За это сообщение автора поблагодарили: Logger (3). |
29.09.2023, 17:37 | #20 |
Участник
|
Цитата:
X++: static void tern_macro_test(Args _args) { #localmacro.tern if (%2) { %1 = %3; } else { %1 = %4; } #endmacro anytype value, firstValue, secondValue; boolean useFirst; ; useFirst = true; firstValue = 1; secondValue = 2; #tern(value, useFirst, firstValue, secondValue) info(strfmt("%1", value)); }
__________________
aLL woRk aNd nO JoY MAKes jAck a dULL Boy |
|
Теги |
ax2012, ax2012r3, тернарный оператор |
|
|