Delphi: передать TObject в массиве вариантов - PullRequest
3 голосов
/ 15 апреля 2009

У меня есть процедура, которая ожидает параметр типа TObject, что-то вроде этого:

MyProcedure (const AValue : TObject);

У меня есть массив Variant, который я перебираю для вызова процедуры, что-то вроде этого:

  for i:=0 to High(myArray) do
    MyProcedure (myArray[i]);

Компилятор выдает ошибку: «Несовместимые типы: TObject и Variant».

Что я могу сделать, чтобы обойти это?

Дополнительная информация: До сих пор я передавал простые типы (строки, числа, даты) в различных массивах (массивы, как правило, представляют собой смесь разных типов - в конечном итоге я передаю их в качестве параметров к хранимой процедуре базы данных). Теперь мне также нужно (в некоторых случаях) передать объект TObject.

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

Ответы [ 4 ]

8 голосов
/ 15 апреля 2009

Вариант не может содержать объекты, он может содержать только примитивные типы, такие как целое число и строка.

Я бы предложил изменить ваш массив на нужный вам тип, а не вариант. Если вы не уверены, какой тип объекта вам нужен, создайте массив TObject или минимально возможный базовый класс объектов, которые будет содержать ваш массив.

3 голосов
/ 15 апреля 2009

Вы не можете хранить простые объекты, это вариант. Но вы можете хранить интерфейсы.

var
  v : Variant;
  i : IInterface;

begin
  v := i; // Works perfectly;
end.

Посмотрите на типы для варианта:

varEmpty    = $0000; { vt_empty        0 }
varNull     = $0001; { vt_null         1 }
varSmallint = $0002; { vt_i2           2 }
varInteger  = $0003; { vt_i4           3 }
varSingle   = $0004; { vt_r4           4 }
varDouble   = $0005; { vt_r8           5 }
varCurrency = $0006; { vt_cy           6 }
varDate     = $0007; { vt_date         7 }
varOleStr   = $0008; { vt_bstr         8 }
varDispatch = $0009; { vt_dispatch     9 }
varError    = $000A; { vt_error       10 }
varBoolean  = $000B; { vt_bool        11 }
varVariant  = $000C; { vt_variant     12 }
varUnknown  = $000D; { vt_unknown     13 }
//varDecimal  = $000E; { vt_decimal     14 } {UNSUPPORTED as of v6.x code base}
//varUndef0F  = $000F; { undefined      15 } {UNSUPPORTED per Microsoft}
varShortInt = $0010; { vt_i1          16 }
varByte     = $0011; { vt_ui1         17 }
varWord     = $0012; { vt_ui2         18 }
varLongWord = $0013; { vt_ui4         19 }
varInt64    = $0014; { vt_i8          20 }
varUInt64   = $0015; { vt_ui8         21 }

Вы можете, если действительно хотите, привести TObject к Pointer к Integer и сохранить его. Но я не уверен, действительно ли ты этого хочешь.

1 голос
/ 15 апреля 2009

Моя первая реакция - спросить, почему вы храните объекты TObject в списке вариантов, но при условии, что у вас есть веская причина!

Если вам удалось разместить свой экземпляр TObject в массиве, то вы, вероятно, поместили указатель на объект Tobject. В этом случае вам нужно указать тип Variant / Integer как объект TO, например

for i:=0 to High(myArray) do
    MyProcedure (TObject(myArray[i]));

Это должно сработать, однако, как и при любом приведении типов, вы должны убедиться, что myArray [i] действительно является указателем на экземпляр TObject, иначе могут произойти ужасные вещи.

Вы уверены, что TList не будет делать то, что вы хотите. Вариант действительно предназначен для хранения фундаментальных типов, таких как string, integer, float, boolean not Objects.

0 голосов
/ 15 апреля 2009

Я не думаю, что это хорошая идея - создать TParam с переменной Variant и переменной TOBject. Что-то вроде:

Tobject = record
  prim: Variant;
  obj: TObject;
end

Работало бы, но мне это кажется очень грязным. Паскаль не типизированный язык, и я не буду относиться к нему как к одному. Я бы предложил либо:

Создайте еще одну функцию для обработки Variant, а также

MyProcedure (const AValue : TObject);

также есть

MyProcedure (const AValue : Variant);

и обрабатывать ваши данные отдельно. Или создайте запись, которая определяет ваши входные данные, например, вместо того, чтобы у TParam варианта и объекта было что-то вроде:

TStoredProcParm = record
  name: String;
  bought: TDateTime;
end;

и так далее. Может быть, у вас так много разных данных, что маршрут варианта / объекта является лучшим, но это выглядит как головная боль при обслуживании - когда ваш другой код проходит массив Variant, как узнать, какой вариант, какой и как использовать из них в вашем сохраненном процессе?

...