Главная » Delphi » Тип Variant

0

В Delphi 2.0 был введен новый мощный тип данных — Variant. В основном его на значение заключалось в поддержке автоматизации OLE  (OLE  Automation), где  тип данных  Variant используется очень  широко. Фактически тип Variant языка  Object Pascal является инкапсуляцией вариантов OLE. Как мы вскоре  убедились, реализация в Delphi  вариантов оказалась полезной и с точки  зрения других аспектов программиро вания.  Object  Pascal является единственным компилируемым языком, в котором для работы с вариантами OLE введен  специализированный тип данных, представляемый как динамический во время  выполнения программы и как статический во время  ее компиляции.

В Delphi 3 для этой  же цели  был введен  еще один  новый тип данных —  OleVariant, полностью идентичный типу  Variant, за исключением того,  что  он  может  содержать лишь те типы, которые совместимы с OLE. Далее в этом разделе тип Variant и отличия между типами данных OleVariant и Variant рассматривается более подробно.

Variant — динамическое изменение типа

Основное назначение типа  Variant —  предоставить возможность объявить пере менную,  тип  которой неизвестен на момент  компиляции. Это  означает, что  настоя щий  тип  такой  переменной может  изменяться в процессе выполнения программы.Например, приведенная ниже программа корректна и будет компилироваться и вы

полняться без ошибок.

var

V: Variant;                 // V – переменная типа Variant

begin

V := ‘Delphi is Great!';// V содержит строку (тип string)

V := 1;                     // V – целое число (тип Integer)

V := 123.34;                // V – вещественное число (тип float)

V := True;                  // V – логическое значение (тип boolean)

V := CreateOleObject(‘Word.Basic’); // V содержит объект OLE

end;

Варианты способны поддерживать все простые типы  Object  Pascal,  такие  как це лые и вещественные числа,  строки, значения даты и времени и т.п. Кроме  того,  они могут  содержать объекты автоматизации  OLE.  Однако   отметим, что  они  не  могут быть ссылками на объекты Object Pascal, но могут ссылаться на неоднородные масси вы,  состоящие из  переменного  количества элементов, имеющих различный  тип  (в том числе они могут быть и другими массивами вариантов).

Структура определения данных типа Variant

Структура определения данных типа Variant описана в модуле System и выгля

дит следующим образом:

TVarType = Word; PVarData = ^TVarData;

{$EXTERNALSYM PVarData} TVarData = packed record

VType: TVarType;

case Integer of

0: (Reserved1: Word;

case Integer of

0: (Reserved2, Reserved3: Word;

case Integer of

varSmallInt: (VSmallInt: SmallInt);

varInteger:                (VInteger: Integer);

varSingle:                 (VSingle: Single);

varDouble:                 (VDouble: Double);

varCurrency: (VCurrency: Currency);

varDate:                   (VDate: TDateTime);

varOleStr:                 (VOleStr: PWideChar);

varDispatch: (VDispatch: Pointer);

varError:                  (VError: LongWord);

varBoolean:                (VBoolean: WordBool);

varUnknown:                (VUnknown: Pointer);

varShortInt: (VShortInt: ShortInt);

varByte:                   (VByte: Byte);

varWord:                   (VWord: Word);

varLongWord: (VLongWord: LongWord);

varInt64:                  (VInt64: Int64);

varString:                 (VString: Pointer);varAny: (VAny: Pointer); varArray:    (VArray: PVarArray); varByRef:      (VPointer: Pointer);

);

1: (VLongs: array[0..2] of LongInt);

);

end;

2: (VWords: array [0..6] of Word);

3: (VBytes: array [0..13] of Byte);Структура  TVarData занимает 16 байт памяти. Первых два байта  этой  структуры содержат слово,  значение которого определяет, на какой  именно тип  данных  ссы лается  вариант. Ниже  приведены конкретные значения, соответствующие различ ным типам  данных, которые могут быть  помещены в поле  VType записи TVarData. Следующие  6 байт  записи не  используются. Последние 8 байт  содержат либо  на стоящие данные, либо указатель  на данные, представляемые этим вариантом. Не обходимо отметить, что  данная  структура  точно соответствует требованиям, предъявляемым к реализации вариантов OLE.

{ Коды типов Variant (wtypes.h) }

varEmpty   = $0000; { vt_empty      } varNull    = $0001; { vt_null       } varSmallint = $0002; { vt_i2         } varInteger = $0003; { vt_i4         } varSingle  = $0004; { vt_r4         } varDouble  = $0005; { vt_r8         } varCurrency = $0006; { vt_cy         } varDate    = $0007; { vt_date       } varOleStr  = $0008; { vt_bstr       } varDispatch = $0009; { vt_dispatch   } varError   = $000A; { vt_error      } varBoolean = $000B; { vt_bool       } varVariant = $000C; { vt_variant    } varUnknown = $000D; { vt_unknown    }

//varDecimal     = $000E; { vt_decimal   } { Не поддерживается }

{ undefined                           $0f } { Не поддерживается }

varShortInt = $0010; { vt_i1         }

varByte    = $0011; { vt_ui1        }

varWord    = $0012; { vt_ui2        }

varLongWord = $0013; { vt_ui4        }

varInt64   = $0014; { vt_i8         }

//varWord64      = $0015; { vt_ui8       } { Не поддерживается }

{ При добавлении новых элементов необходимо модифицирвать varLast, BaseTypeMap и OpTypeMap вариантов }

varStrArg  = $0048; { vt_clsid      }

varString  = $0100; { Строка Pascal; с OLE несовместима }

varAny     = $0101; { Любой Corba }

varTypeMask = $0FFF;

varArray   = $2000;

varByRef   = $4000;

НА ЗАМЕТКУ

Как можно заметить из вышеприведенного кода, Variant не может содержать ссылку на данные типа Pointer или class.

Из описания структуры  записи TVarData видно,  что  она  действительно может  со держать данные  любого типа. Следует отличать приведенную выше запись TVarData от действительных данных типа Variant. Хотя запись  переменного состава  и данные ти па Variant (вариант) внешне схожи  по своему назначению, они  представляют две со вершенно разные конструкции. Запись TVarData позволяет хранить данные  различных типов в одной и той же области памяти (подобно объединениям — union языка C/C++). Более подробная информация по этой теме приведена далее в настоящей главе. Опера тор case в описании записи TVarData служит для определения типов  данных, которые может представлять вариант. Так, если в поле VType содержится значение varInteger, то только  четыре из восьми  байтов  данных  записи будут содержать хранимое перемен ной целое  значение. Подобным образом, если в поле VType содержится значение var- Byte, только  один из восьми байтов  области данных будет использоваться для хранения значения.

Обратите внимание, если VType содержит значение varString, то восемь  байтов данных  в записи содержат не  реальную  строку,  а лишь  указатель  на нее.  Это  очень важно  понимать, поскольку  при  работе с вариантами можно  получить  непосредст венный доступ к значениям любого поля, как показано в приведенном ниже примере.

var

V: Variant;

begin

TVarData(V).VType := varInteger;

TVarData(V).VInteger := 2;

end;

Следует  отдавать себе  отчет в том,  что  такое  использование варианта —  опасная игра,  так  как при  этом,  например, можно  легко  разрушить указатель  на строку  или другой объект с управляемым временем жизни. В результате объект станет недоступ ным для процессов “уборки мусора”, что приведет к утечке памяти (leaking memory) и потере других ресурсов приложения. Более  подробная информация о процессах “уборки мусора” приведена в следующем разделе.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии