При работе с компонентами ActiveX и COM интерфейсами в Delphi часто используется тип OleVariant для передачи значений. Однако, при использовании RTTI (Runtime Type Information) может возникать проблема, когда значение типа TDateTime передается в свойство OleVariant объекта и вместо ожидаемого типа TDateTime оно интерпретируется как тип Float. Это приводит к тому, что в дальнейшем при выполнении операций с таким значением используются правила для работы с плавающей точкой, вместо специфических для TDateTime.
Описание проблемы
Рассмотрим код, который использует RTTI для установки свойства объекта через OleVariant:
class procedure TRTTI.SetObjPropValue(obj: TObject; rprop: TRttiProperty; value: OleVariant);
var
rtyp: TRttiType;
vt: TVarType;
begin
// ...
case rprop.PropertyType.TypeKind of
tkVariant:
// Здесь передается значение TDateTime
rprop.SetValue(obj, TValue.FromVariant(value));
// Объект получает значение типа Float
end;
// ...
end;
Проблема заключается в том, что, несмотря на то, что TDateTime встроенный в Delphi представляется как тип Float, при использовании RTTI происходит неверное преобразование типа, и объект получает значение не в виде TDateTime, а в виде Float.
Анализ ситуации
В типе Variant и OleVariant хранятся значения по-разному. В коде, который не взаимодействует напрямую с ActiveX/COM объектами, рекомендуется использовать Variant. Однако, в контексте Delphi, при передаче значения TDateTime в OleVariant, компилятор корректно вызывает функцию VarFromTDateTime, и TValue.FromVariant должен был корректно обработать это значение, что было бы видны как случай обработки даты в TValue (который обрабатывается через varDate case label).
Предложенное решение
Проблема в том, что при использовании TValue.FromVariant происходит неявное преобразование типа, и внутреннее значение TValue уже хранит тип данных, а не само значение типа Variant. В случае с TDateTime, который в Delphi является "оберткой" для Float, происходит преобразование именно в Float, а не сохраняется информация о типе TDateTime.
Решение: не использовать TValue.FromVariant, а передать значение прямо, как есть, через TValue.From<Variant>(value). Это позволяет избежать нежелательных преобразований типов и сохранить значение в виде Variant для дальнейшей корректной обработки свойством объекта.
Подтвержденное решение
Проблема была подтверждена, и заключается в том, что TValue.FromVariant некорректно обрабатывает тип TDateTime, сохраняя лишь его числовое значение без информации о типе, что приводит к потере типизированности. Использование TValue.From<Variant> с сохранением исходного значения Variant решает проблему. Это также подтверждено через отчет о проблеме в системе отслеживания ошибок Embacadero: RSP-21176.
Выводы
Пользователям Delphi, сталкивающимся с подобными проблемами при работе с RTTI и OleVariant, следует внимательно следить за типами данных и не использовать неявные преобразования, которые могут привести к потере типизации. Использование прямой передачи значений в виде Variant через TValue.From<Variant> позволит избежать подобных ошибок типов.
Ошибка типов возникает в Delphi при назначении свойству `OleVariant` значения типа `TDateTime` через RTTI, из-за неверного преобразования типа и потери информации о типизации.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.