




Это просто мнение, основанное на моем опыте с тем, какие варианты можно и чего нельзя делать.
Если вы поместите в него COM-объект, он будет сохранен как ссылка IDispatch, и, таким образом, любые вызовы методов или свойства, к которым вы обращаетесь на этом объекте, будут преобразованы в некоторый код, который ищет внутренний DISPID метода / свойства, массив с аргументами метода, и метод будет вызываться через интерфейс IDispatch.
Другими словами, IDispatch обрабатывается за вас, как обычно, но компилятор делает это автоматически.
Однако с обычными объектами Delphi все становится сложнее. Вы можете использовать RTTI для поиска и вызова опубликованных методов и свойств, но это все. Если у вас есть имя неопубликованного, не виртуального метода, Delphi не сможет найти для него правильный адрес в вашем методе.
Другими словами, все, что вы могли бы сделать, это просто держать объект, вы не сможете его использовать. Возможно, они могли бы добавить поддержку для того, чтобы просто освободить его, но, опять же, вероятно, это все.
Я точно знаю, что если вы правильно реализуете IDispatch, вы можете безопасно хранить и использовать объект через вариант. У меня есть класс, который можно использовать в качестве базового класса для объектов Delphi, с которыми вы хотите это сделать. Он автоматически предоставит опубликованные методы / свойства, и вы можете добавить больше, если хотите, через вызовы некоторых защищенных методов. Если есть интерес к такому классу, могу где-нибудь разместить.
Но опять же, это через IDispatch, и он использует опубликованные методы, остальное - это ручной код, поэтому поддержка вариантов должна быть встроена в ваши объекты вами.
Вот почему я думаю, что они просто сказали: это вызовет жалобы, что мы можем удерживать объект, но это бесполезно.
Но это только мои мысли. Возможно, у кого-то из официальных лиц есть ответ лучше.
+1 Робу: TCustomVariantType и TInvokeableVariantType довольно эффективны. Некоторые потери производительности, но которые можно обойти с помощью низкоуровневого взлома.
Вы определенно можете хранить объект внутри переменной Variant - просто добавьте его в NativeUInt. В любом случае объект - это просто указатель.
obj := TObject.Create;
v := NativeUInt(obj);
obj := TSomeObject(NativeUInt(v));
Раньше я использовал Variants для хранения объектов, используя внутренние компоненты Variant, код выглядит примерно так:
var
MyObject: TMyObject;
Value: Variant;
begin
MyObject:= TMyObject.Create;
TVarData(Value).VType:= VarByRef or VarUnknown;
TVarData(Value).VPointer:= MyObject;
Обратите внимание, что вы обманываете. VarByRef - это флаг, предназначенный для изменения поля базового типа. В вашем коде указано, что переменная - пустой, но она пуста по ссылке.
Думаю, концептуально это нормально; логически нетипизированная ссылка на местоположение эквивалентна нетипизированному указателю, то есть void * в C или Pointer в Delphi.
Для правильной работы в Delphi должен быть varByRef or varVariant.
VarByRef - это флаг в четырех верхних битах типа. Поскольку флаг VarByRef устанавливается сам по себе для типа, младшие двенадцать битов, которые содержат фактический тип, будут равны нулю, что для варианта означает целое число типа. Лучше установить тип varByRef | varUnknown - действительно то, что это такое, указатель на тип, неизвестный варианту.
Вы почти правы. Также следует упомянуть классы TCustomVariantType и TInvokeableVariantType. Эти классы показывают все, что класс должен сделать, чтобы иметь возможность быть использовал (а не просто хранить) в Variant без обязательной реализации IDispatch.