|  | 
|  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, тернарный оператор | 
|  | 
| 
 |