Думаю многие сталкивались с тем, что иногда требуется в variant передавать blob, ну или TObject. В таких языках как Java и C# все проще, элементарные типы являются объектами ну или умеют упаковываться из значимых типов в объекты. Для всех типов в языке есть базовый тип. В Delphi же, когда тип на этапе компиляции не известен единственным универсальным решением является использование variant.
Но не все так гладко, тип Variant предназначен только для хранения простых типов и указатель на объект в него не поместить не используя грязных хаков. Хотя сам RTL ими так и кишит. Так для хранения ftBlob в variant используется строка.
На самом деле есть "законный" механизм как через Variant передавать любые данные, в том числе и объекты. Для этого есть базовый класс TCustomVariantType, на основе которого можно определить свой тип который можно будет передавать как Variant, перекрыть в нем бинарные арифметические и логические операции. Т.е. реализовать например свое сравнению и сложение для экземпляров типа.
Но вот тут мы подходим к самому интересному, в FireMonkey появились методы по преобразованию variant к TObject и обратно:
function VarIsObject(Value: Variant): Boolean; function ObjectToVariant(const AObject: TObject): Variant; function VariantToObject(const Value: Variant): TObject;
Выглядит интригующе, неправда ли?
Но что внутри?
Совершенно обычный хак, все опять сделано через строки:
function ObjectToVariant(const AObject: TObject): Variant; begin Result := 'vgobj' + IntToStr(Integer(Pointer(AObject))); end; function VariantToObject(const Value: Variant): TObject; var S: string; begin S := Value; {$IFDEF FPCCOMP} if (S <> '') and (Pos(WideString('vgobj'), S) = 1) then {$ELSE} if (S <> '') and (Pos('vgobj', S) = 1) then {$ENDIF} Result := TObject(Pointer(StrToInt(Copy(S, 6, 10)))) else Result := nil; end;
...и расположено это все не в модули System или Variants, а в Types. Никакой поддержки на уровне компилятора нет. Т.е. все еще нельзя писать такvar v: Variant; begin v := TMyClass.Create(); end;
Почему бы Embarcadero уже не реализовать нормальную поддержку объектов в variant, ну или хотя бы сделать на основе TCustomVariantType. Непонятно. Притом, что есть и наследники от него TInvokeableVariantType и TPublishableVariantType.
Возможно, все ради совместимости с COM Variant, не хотят далеко от него уходить и пытаются сохранить Variant для типов передающихся по значению. Или, возможно, методы VariantToObject и ObjectToVariant были реализованы Евгением Крюковым KSDev, а в Embarcadero не стали ничего переделывать, работает и на том спасибо.