Почему варианты Delphi не могут содержать объекты?

Почему варианты Delphi не могут содержать объекты? Что еще более важно, в чем причина этого ограничения?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
14
0
8 295
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Это просто мнение, основанное на моем опыте с тем, какие варианты можно и чего нельзя делать.

Если вы поместите в него COM-объект, он будет сохранен как ссылка IDispatch, и, таким образом, любые вызовы методов или свойства, к которым вы обращаетесь на этом объекте, будут преобразованы в некоторый код, который ищет внутренний DISPID метода / свойства, массив с аргументами метода, и метод будет вызываться через интерфейс IDispatch.

Другими словами, IDispatch обрабатывается за вас, как обычно, но компилятор делает это автоматически.

Однако с обычными объектами Delphi все становится сложнее. Вы можете использовать RTTI для поиска и вызова опубликованных методов и свойств, но это все. Если у вас есть имя неопубликованного, не виртуального метода, Delphi не сможет найти для него правильный адрес в вашем методе.

Другими словами, все, что вы могли бы сделать, это просто держать объект, вы не сможете его использовать. Возможно, они могли бы добавить поддержку для того, чтобы просто освободить его, но, опять же, вероятно, это все.

Я точно знаю, что если вы правильно реализуете IDispatch, вы можете безопасно хранить и использовать объект через вариант. У меня есть класс, который можно использовать в качестве базового класса для объектов Delphi, с которыми вы хотите это сделать. Он автоматически предоставит опубликованные методы / свойства, и вы можете добавить больше, если хотите, через вызовы некоторых защищенных методов. Если есть интерес к такому классу, могу где-нибудь разместить.

Но опять же, это через IDispatch, и он использует опубликованные методы, остальное - это ручной код, поэтому поддержка вариантов должна быть встроена в ваши объекты вами.

Вот почему я думаю, что они просто сказали: это вызовет жалобы, что мы можем удерживать объект, но это бесполезно.

Но это только мои мысли. Возможно, у кого-то из официальных лиц есть ответ лучше.

Вы почти правы. Также следует упомянуть классы TCustomVariantType и TInvokeableVariantType. Эти классы показывают все, что класс должен сделать, чтобы иметь возможность быть использовал (а не просто хранить) в Variant без обязательной реализации IDispatch.

Rob Kennedy 14.12.2008 20:34

+1 Робу: TCustomVariantType и TInvokeableVariantType довольно эффективны. Некоторые потери производительности, но которые можно обойти с помощью низкоуровневого взлома.

Arnaud Bouchez 10.10.2013 10:47

Вы определенно можете хранить объект внутри переменной 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 - это флаг, предназначенный для изменения поля базового типа. В вашем коде указано, что переменная - пустой, но она пуста по ссылке.

Rob Kennedy 14.12.2008 20:29

Думаю, концептуально это нормально; логически нетипизированная ссылка на местоположение эквивалентна нетипизированному указателю, то есть void * в C или Pointer в Delphi.

Barry Kelly 21.01.2009 09:13

Для правильной работы в Delphi должен быть varByRef or varVariant.

user2091150 06.04.2015 16:53

VarByRef - это флаг в четырех верхних битах типа. Поскольку флаг VarByRef устанавливается сам по себе для типа, младшие двенадцать битов, которые содержат фактический тип, будут равны нулю, что для варианта означает целое число типа. Лучше установить тип varByRef | varUnknown - действительно то, что это такое, указатель на тип, неизвестный варианту.

Kurt Fitzner 12.01.2017 15:17

Другие вопросы по теме