Передать значение TDateTime в свойство OleVariant через RTTI - PullRequest
0 голосов
/ 04 сентября 2018

Когда я присваиваю значение TDateTime свойству OleVariant объекта, используя RTTI, объект становится значением Float.

Объект спроектирован так, что это свойство может принимать значение Null или значение любого типа данных. Если оно становится плавающим, то результат должен быть рассчитан как разница чисел с плавающей точкой. Если он становится равным TDateTime, то результат должен быть рассчитан как разница двух TDateTime значений.

Если бы я передал значение непосредственно ему, оно будет работать нормально, но в середине RTTI.

Я знаю, что TDateTime внутренне представлен как float, но есть ли возможность получить именно тот тип данных, который я отправляю?

Пожалуйста, посмотрите на случай tkVariant в следующем примере кода:

class procedure TRTTI.SetObjPropValue(obj: TObject; rprop: TRttiProperty; value: OleVariant);
var
  rtyp: TRttiType;
  vt: TVarType;
begin
  if obj = nil then Exit();
  if (rprop <> nil) and (rprop.IsWritable) then begin
    case rprop.PropertyType.TypeKind of
      tkInteger, tkInt64:
        begin
          value := TVarConv.NullableCurr(value);
          if VarIsNumeric(value) then rprop.SetValue(obj, TValue.FromVariant(Trunc(value)));
        end;
      tkFloat:
        begin
          if rprop.PropertyType.Name = 'TDateTime' then
            value := TVarConv.NullableDateTime(value)
          else
            value := TVarConv.NullableFloat(value);
          if not VarIsNull(value) then rprop.SetValue(obj, TValue.FromVariant(value));
        end;
      tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
        begin
          rprop.SetValue(obj, TValue.FromVariant(VarToStr(value)));
        end;
      tkEnumeration:
        begin
          if rprop.PropertyType.Name = 'Boolean' then
            value := TVarConv.NullableBool(value)
          else
            value := null;
          if not VarIsNull(value) then rprop.SetValue(obj, TValue.FromVariant(value));
        end;
      tkVariant:
        //Here I transmit the TDateTime value
        rprop.SetValue(obj, TValue.FromVariant(value));
        //An object receives Float
    end;
  end;
end;

1 Ответ

0 голосов
/ 04 сентября 2018

Проблема здесь в том, что TValue.FromVariant внутренне "распаковывает" переданный Variant, сохраняя базовое значение внутри TValue. В вашем случае он правильно замечает, что TDateTime хранится в Variant и сохраняет его как TDateTime.

Когда вы передаете это TValue, содержащее TDateTime (который имеет TypeKind tkFloat), к SetValue из TRttiProperty, оно выполняет преобразование в тип свойства, которое Variant - см. System.Rtti.Conv2Variant. Этот метод игнорирует тот факт, что tkFloat может быть TDateTime, но просто помещает Variant, в котором сохраняется результат с плавающей запятой.

Решение простое: не используйте TValue.FromVariant, а просто TValue.From<Variant>(value). Таким образом, вы сохраняете значение Variant внутри TValue и передаете его без каких-либо ненужных неявных преобразований типов в установщик.

Отмечено как https://quality.embarcadero.com/browse/RSP-21176

...