11.11.2023, 18:37 | #1 |
Участник
|
DAX2012 тип dot net System.Object и тип X++ real с CIL как правильно работать?
Добрый день.
Есть работа с внешней базой, используется System.Data.SqlClient.SqlDataReader. Его свойство Item[...] (в Аксе используем метод get_Item(...)) возвращает System.Object. Для полей вещественных типов возвращается System.Double. Для получения значений Аксы вполне работал способ: X++: System.Object sysObj;
anytype ret;
sysObj = dataReader.get_Item(_fieldNum);
ret = ClrInterop::getAnyTypeForObject(_sysObj); Естественно, понять что именно не работает удалось только в отладчике VS. Понятно, что конкретный случай получилось обойти путем написания кучи кода: X++: protected anytype systemObjectToAnyType(System.Object _sysObj) { anytype ret; System.Type retType; str retTypeName; str valueStr; boolean useStdConvert; ; useStdConvert = true; if (xSession::isCLRSession()) { retType = _sysObj.GetType(); retTypeName = retType.get_Name(); if (retTypeName == 'double') { // Весёлости взаимодействия System.Double и real X++. // Стандарт не конвертирует, приходится выполнять закат солнца вручную. valueStr = _sysObj.ToString(); ret = str2num_RU(valueStr); useStdConvert = false; } } if (useStdConvert) { // BP deviation documented ret = ClrInterop::getAnyTypeForObject(_sysObj); } return ret; } В стандартном приложении нашел много кода, когда наоборот - имеем переменную real X++ и нужно передать туда, где требуется System.Double - даже в global метод для этого создали. Видимо сталкивались с проблемами преобразования в CIL real->System.Double. А вот ситуации когда имеем System.Double и нужно просто присвоить её real X++ не обнаружил. |
|
11.11.2023, 18:47 | #2 |
Участник
|
Вообще, даже в методе nullValueBaseType класса Global пришлось делать "затычку":
Объявить переменную: RealBase realValue; Далее: X++: case Types::Real: // FIX klimov 10.11.2023 --> if (xSession::isCLRSession()) { // Весёлый CIL. // Если просто вернуть 0.0 в anytype, то в CIL вернется объект System.Double. // А если не вызывать Convert, то будет не 0, а 0.___значение (типа 0.0000000000578). realValue = System.Convert::ToDouble(0.0); return realValue; } else { // FIX klimov 10.11.2023 <-- return 0.0; } X++: recordStruct.add(fieldName, nullValueBaseType(fieldType)); |
|
11.11.2023, 22:05 | #3 |
Участник
|
Встречал похожие приколы в других местах.
Были проблемы для anytype для неинициализированных значений. Может у вас там null приходил ? а если просто присвоить значение ? Например real retReal; retReal = _sysObj; // или так retReal = _sysObj as System.Double; // или так retReal = any2real(_sysObj as System.Double); ret = retReal; |
|
|
За это сообщение автора поблагодарили: Raven Melancholic (2). |
12.11.2023, 14:23 | #4 |
Участник
|
Насколько я понимаю real соответствует типу System.Decimal, а не System.Double (https://learn.microsoft.com/en-us/dy...eveloper/reals).
Думается, что если использовать Decimal, то должно работать нормально (т.е. возвращать real): X++: if (sysObj is System.Double)
{
ret = ClrInterop::getAnyTypeForObject(System.Convert::ToDecimal(sysObj));
} Интересно почему он 0.0 в nullValueBaseType конвертирует в System.Double, а не в System.Decimal. А если вот такой код будет, то он также будет возвращать System.Double ? X++: if (xSession::isCLRSession()) { return realValue; }
__________________
Sergey Nefedov |
|
|
За это сообщение автора поблагодарили: Logger (5), Raven Melancholic (2). |
12.11.2023, 16:22 | #5 |
Участник
|
Цитата:
Думается, что если использовать Decimal, то должно работать нормально (т.е. возвращать real).
Цитата:
Интересно почему он 0.0 в nullValueBaseType конвертирует в System.Double, а не в System.Decimal.
Цитата:
Согласен с Logger, any2real тоже выглядит вполне рабочим вариантом
Может и рабочий, но получаем ошибку (ловится в VS) "Неправильный тип аргумента функции преобразования." |
|
12.11.2023, 16:26 | #6 |
Участник
|
Ну и Decimal - Double в CIL уже народ сталкивался:
Поле "XXX" (= -0,000) может содержать только положительные числа |
|
15.11.2023, 00:38 | #7 |
Участник
|
Добрый вечер.
Тоже пользуемся данной библиотекой, но используем функцию getValue. Суть одна и та же, она возвращает тот же самый Object. Однако, в отличии от использования унифицированной функции работающей с anyType (который, между прочим, есть тот самый System.Object) выделили набор функций для приведения результата к типам Аксапты. Logger выше писал, просто разовью мысль: Для real своя функция valueToReal, для string - valueToString и тд. Здесь стоит акцентировать внимание на том, что в функции необходимо использовать результирующую переменную, в ином случае вернется всё тот же System.Object. Т.е.: X++: public string valueToString(... _reader, _columnIndex) { string ret; ; if (_reader.IsDBNull(_columnIndex)) { ret = _reader.GetValue(_columnIndex); } return ret; } X++: public string valueToString(... _reader, _columnIndex) { return _reader.IsDBNull(_columnIndex) ? "" : _reader.GetValue(_columnIndex); } Последний раз редактировалось Товарищ ♂uatr; 15.11.2023 в 00:41. |
|
|
За это сообщение автора поблагодарили: Raven Melancholic (10). |
15.11.2023, 10:23 | #8 |
Участник
|
Отлично!
А как вы определяете какую из функций вызвать в случае, если не знаете заранее тип? Что-то мне использование System.Type с получением наименования: X++: retType = _sysObj.GetType(); retTypeName = retType.get_Name(); if (retTypeName == '...') |
|
15.11.2023, 12:44 | #9 |
Участник
|
В рамках существующих интеграций знаем типы данных...
...придется фантазировать: Особой вариативности не вижу, потому что за капотам используется внутренний объект и доступа к нему из вне нет (System.Data.SqlClient._SqlMetaData). Остается использовать то, что есть - System.Type. Его можно получить, как минимум 2 способами: - из reader'a (функция GetFieldType); - из самого объекта, что и делаете. С точки зрения эстетики Guid куда приятнее - для объекта типа System.Type функция get_GUID. GUID'ы типов данных можно обернуть в макросы. Встречал реализацию, где сравнивается сам System.Type, но то с чем он сравнивается нужно держать в памяти. |
|
15.11.2023, 15:04 | #10 |
Участник
|
Гугл подсказал, что данный способ является оптимальным, C#:
X++: System.Type type = reader.GetFieldType(c); switch (Type.GetTypeCode(type)) { case TypeCode.DateTime: break; case TypeCode.String: break; default: break; } |
|
|
За это сообщение автора поблагодарили: Logger (5). |
30.11.2023, 14:10 | #11 |
Участник
|
Цитата:
AIF + Web Services + JSON в 2009-й была проблема, в 12-ке - нет. Возможно как-то завязано на версию .Net |
|
|
За это сообщение автора поблагодарили: SRF (2). |
01.12.2023, 09:24 | #12 |
Участник
|
Да, это видел.
А так же Поле "XXX" (= -0,000) может содержать только положительные числа Правда по теме я ступил. Сам же три года назад писал разные методы для разных типов NET при обмене с внешней базой. Просто они в другом классе-обертке. |
|
01.12.2023, 10:24 | #13 |
Участник
|
Так какое же решение выбрали?
|
|
|
|