На этом шаге мы рассмотрим правила выполнения бинарных операций над значениями вариантного типа.
Если один из операндов бинарной операции имеет тип Variant, второй операнд автоматически преобразуется к вариантному типу, результатом выполнения арифметико-логических операций будет значение вариантного типа, а результатом операций отношения - значение тпа Boolean. Исключение составляют случаи, когда среди операндов есть операнд со значением Unassigned или Null. В первом случае (значение Unassigned) для операндов допустимы только операции отношения, а во втором случае (значение Null) результатом операции всегда будет Null.
Бинарные операции над операндами типа Variant выполняются в три этапа.
Приведем таблицу определения общего типа по типам первого и второго операндов.
Тип значения второго вариантного операнда | |||||||
---|---|---|---|---|---|---|---|
Integer | Double | Currency | String | Boolean | Date | ||
Тип значения первого вариантного операнда |
Integer | Integer | Double | Currency | Double | Integer | Date |
Double | Double | Double | Currency | Double | Double | Date | |
Currency | Currency | Currency | Currency | Currency | Currency | Date | |
String | Double | Double | Currency | String | Boolean | Date | |
Boolean | Integer | Double | Currency | Boolean | Boolean | Date | |
Date | Date | Date | Date | Date | Date | Date |
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; . . . Label24: TLabel; Label25: TLabel; Button1: TButton; Edit1: TEdit; Edit2: TEdit; . . . Edit95: TEdit; Edit96: TEdit; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} var Switch:Integer; function GetCodeName(V : Variant): String; { Функция возвращает идентификатор кода вариантного типа} type TypeCodeNames = array [$0000..$000D] of String; const CodeNames: TypeCodeNames = ('varEmpty','varNull','varSmallint','varInteger', 'varSingle','varDouble', 'varCurrency','varDate', 'varOleStr','varDispatch','varError','varBoolean', 'varVariant','varUnknown'); var Code : Integer; begin Code := VarType(V) and varTypeMask; case Code of $0000..$000D: Result:= CodeNames[Code]; $0011: Result:='varByte'; $0100: Result:='varString'; $0FFF: Result:='varTypeMask'; $2000: Result:='varArray'; else Result :='varError'; end; end; procedure PrintOperand (Op: Variant; Ed1,Ed2:TEdit); { Процедура печатает идентификатор кода операнда } { вариантного типа и значение этого операнда в заданных} { полях Ed1 и Ed2 } var CodeName, S : String; begin CodeName := GetCodeName(Op); Ed1.Text := CodeName; if CodeName <> 'varString' then Str(Op:10:4, S) else S := Op; Ed2.Text := S; end; procedure MyAdd (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию сложения над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl + Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure MySubstr (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию вычитания над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl - Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure MyMult (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию умножения над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl * Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure MyDivide (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию деления над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl / Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure MyShl (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию сдвига влево над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl shl Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure MyAnd (Opl,Op2: Variant; Ed1,Ed2:TEdit); { Процедура вьполняет операцию поразрядного умножения над заданными } { операндами вариантного типа Opl и 0р2, а также печатает } { идентификатор кода операнда вариантного типа и значение } { этого операнда в полях Edl й Ed2} var Res : Variant; S : String; begin try Res := Null; Res := Opl and Op2; Ed1.Text := GetCodeName (Res); Str (Res:10:4, S); Ed2.Text := S; except on EVariantError do begin Ed1.Text := 'Error'; Ed2.Text := 'Error'; end; end; end; procedure TForm1.Button1Click(Sender: TObject); var Op1, Op2 : Variant; Integer1,Integer2 : Integer; Double1, Double2 : Double; Currency1, Currency2 : Currency; TDateTime1, TDateTime2 : TDateTime; procedure FirstColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования первой } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit1, Edit2); PrintOperand (Op2, Edit3, Edit4); MyAdd (Op1, Op2, Edit5, Edit6); MySubstr (Op1, Op2, Edit7, Edit8); MyMult (Op1, Op2, Edit9, Edit10); MyDivide (Op1, Op2, Edit11, Edit12); MyShl (Op1, Op2, Edit13, Edit14); MyAnd (Op1, Op2, Edit15, Edit16); end; procedure SecondColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования второй } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit17, Edit18); PrintOperand (Op2, Edit19, Edit20); MyAdd (Op1, Op2, Edit21, Edit22); MySubstr (Op1, Op2, Edit23, Edit24); MyMult (Op1, Op2, Edit25, Edit26); MyDivide (Op1, Op2, Edit27, Edit28); MyShl (Op1, Op2, Edit29, Edit30); MyAnd (Op1, Op2, Edit31, Edit32); end; procedure ThirdColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования третьей } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit33, Edit34); PrintOperand (Op2, Edit35, Edit36); MyAdd (Op1, Op2, Edit37, Edit38); MySubstr (Op1, Op2, Edit39, Edit40); MyMult (Op1, Op2, Edit41, Edit42); MyDivide (Op1, Op2, Edit43, Edit44); MyShl (Op1, Op2, Edit45, Edit46); MyAnd (Op1, Op2, Edit47, Edit48); end; procedure FourthColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования четвертой } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit49, Edit50); PrintOperand (Op2, Edit51, Edit52); MyAdd (Op1, Op2, Edit53, Edit54); MySubstr (Op1, Op2, Edit55, Edit56); MyMult (Op1, Op2, Edit57, Edit58); MyDivide (Op1, Op2, Edit59, Edit60); MyShl (Op1, Op2, Edit61, Edit62); MyAnd (Op1, Op2, Edit63, Edit64); end; procedure FifthColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования пятой } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit65, Edit66); PrintOperand (Op2, Edit67, Edit68); MyAdd (Op1, Op2, Edit69, Edit70); MySubstr (Op1, Op2, Edit71, Edit72); MyMult (Op1, Op2, Edit73, Edit74); MyDivide (Op1, Op2, Edit75, Edit76); MyShl (Op1, Op2, Edit77, Edit78); MyAnd (Op1, Op2, Edit79, Edit80); end; procedure SixthColumn (Op1, Op2 : Variant); { Процедура вычисляет значения для формирования шестой } { колонки таблицы и заносит их в соответствующие поля } { редактирования } begin PrintOperand (Op1, Edit81, Edit82); PrintOperand (Op2, Edit83, Edit84); MyAdd (Op1, Op2, Edit85, Edit86); MySubstr (Op1, Op2, Edit87, Edit88); MyMult (Op1, Op2, Edit89, Edit90); MyDivide (Op1, Op2, Edit91, Edit92); MyShl (Op1, Op2, Edit93, Edit94); MyAnd (Op1, Op2, Edit95, Edit96); end; begin {TForm1.Button1} case Switch of 0: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varInteger'; Integer1 := 4; Integer2 := 2; Op1 := Integer1; Op2 := Integer2; FirstColumn(Op1,Op2); Integer1 := 4; Double2 := 2; Op1 := Integer1; Op2 := Double2; SecondColumn(Op1,Op2); Integer1 := 4; Currency2 := 2; Op1 := Integer1; Op2 := Currency2; ThirdColumn(Op1,Op2); Integer1 := 4; Op1 := Integer1; Op2 := '2'; FourthColumn(Op1,Op2); Integer1 := 4; Op1 := Integer1; Op2 := True; FifthColumn(Op1,Op2); Integer1 := 4; TDateTime2 := 35431; Op1 := Integer1; Op2 := TDateTime2; SixthColumn(Op1,Op2); Inc(Switch); end; 1: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varDouble'; Double1 := 4; Integer2 := 2; Op1 := Double1; Op2 := Integer2; FirstColumn(Op1,Op2); Double1 := 4; Double2 := 2; Op1 := Double1; Op2 := Double2; SecondColumn(Op1,Op2); Double1 := 4; Currency2 := 2; Op1 := Double1; Op2 := Currency2; ThirdColumn(Op1,Op2); Double1 := 4; Op1 := Double1; Op2 := '2'; FourthColumn(Op1,Op2); Double1 := 4; Op1 := Double1; Op2 := True; FifthColumn(Op1,Op2); Double1 := 4; TDateTime2 := 35431; Op1 := Double1; Op2 := TDateTime2; SixthColumn(Op1,Op2); Inc(Switch); end; 2: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varCurrency'; Currency1 := 4; Integer2 := 2; Op1 := Currency1; Op2 := Integer2; FirstColumn(Op1,Op2); Currency1 := 4; Double2 := 2; Op1 := Currency1; Op2 := Double2; SecondColumn(Op1,Op2); Currency1 := 4; Currency2 := 2; Op1 := Currency1; Op2 := Currency2; ThirdColumn(Op1,Op2); Currency1 := 4; Op1 := Currency1; Op2 := '2'; FourthColumn(Op1,Op2); Currency1 := 4; Op1 := Currency1; Op2 := True; FifthColumn(Op1,Op2); Currency1 := 4; TDateTime2 := 35431; Op1 := Currency1; Op2 := TDateTime2; SixthColumn(Op1,Op2); Inc(Switch); end; 3: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varString'; Integer2 := 2; Op1 := '4'; Op2 := Integer2; FirstColumn(Op1,Op2); Double2 := 2; Op1 := '4'; Op2 := Double2; SecondColumn(Op1,Op2); Currency2 := 2; Op1 := '4'; Op2 := Currency2; ThirdColumn(Op1,Op2); Op1 := '4'; Op2 := '2'; FourthColumn(Op1,Op2); Op1 := '4'; Op2 := True; FifthColumn(Op1,Op2); TDateTime2 := 35431; Op1 := '4'; Op2 := TDateTime2; SixthColumn(Op1,Op2); Inc(Switch); end; 4: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varBoolean'; Integer2 := 2; Op1 := True; Op2 := Integer2; FirstColumn(Op1,Op2); Double2 := 2; Op1 := True; Op2 := Double2; SecondColumn(Op1,Op2); Currency2 := 2; Op1 := True; Op2 := Currency2; ThirdColumn(Op1,Op2); Op1 := True; Op2 := '2'; FourthColumn(Op1,Op2); Op1 := True; Op2 := True; FifthColumn(Op1,Op2); TDateTime2 := 35431; Op1 := True; Op2 := TDateTime2; SixthColumn(Op1,Op2); Inc(Switch); end; 5: begin Form1.Caption := 'Таблица преобразования вариантных ' + ' типов для varDate'; TDateTime1 := 35431; Integer2 := 2; Op1 := TDateTime1; Op2 := Integer2; FirstColumn(Op1,Op2); TDateTime1 := 35431; Double2 := 2; Op1 := TDateTime1; Op2 := Double2; SecondColumn(Op1,Op2); TDateTime1 := 35431; Currency2 := 2; Op1 := TDateTime1; Op2 := Currency2; ThirdColumn(Op1,Op2); TDateTime1 := 35431; Op1 := TDateTime1; Op2 := '2'; FourthColumn(Op1,Op2); TDateTime1 := 35431; Op1 := TDateTime1; Op2 := True; FifthColumn(Op1,Op2); TDateTime1 := 35431; TDateTime2 := 35431; Op1 := TDateTime1; Op2 := TDateTime2; SixthColumn(Op1,Op2); Switch:=0; end; end; {Case} end; {TForm1.Button1} procedure TForm1.FormCreate(Sender: TObject); begin Form1.Caption := 'Демонстрация преобразования '+ ' вариантных типов'; end; initialization Switch:=0; end.
В результате выполнения проекта, использующего приведенный модуль, при нажатии на кнопку будут поочередно появляться на экране шесть таблиц, одна из которых изображена на рисунке 1:
Рис.1. Пример работы приложения
Операции отношения (=, <>, <, >, <=, >=) выполняются в следующем порядке. Сначала оба операнда преобразуются к общему типу, а затем над полученными значениями выполняется операция, результатом которой будет значение булевского типа.
Стандартные значения вариантных переменных Unassigned и Null состоят в таком отношении к прочим возможным значениям:
Unassigned < Null < ЛюбоеДругоеЗначение
На следующем шаге мы рассмотрим выполнение унарных операций над значениями вариантного типа.