Преобразование типов значений Null и Unassigned типа Variant в Delphi
Конвертация Unassigned
Если переменная с типом Variant
не инициализирована то она имеет значение Unassigned
, даже если это поле класса:
type
TMyClass = class
FVar: Variant;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
Obj: TMyClass;
Flag: Boolean;
begin
Obj := TMyClass.Create;
try
Flag := Obj.FVar = Unassigned;
ShowMessage(BoolToStr(Flag, True)); // True
finally
FreeAndNil(Obj);
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Возможны следующие случаи преобразования Unassigned
в другие типы данных:
procedure TForm1.Button1Click(Sender: TObject);
var
v: Variant;
i: Integer;
s: string;
b: Boolean;
d: TDateTime;
begin
i := v; // 0
s := v; // пустая строка
b := v; // False
d := v; // 30.12.1899
ShowMessage(IntToStr(i));
ShowMessage(s);
ShowMessage(BoolToStr(b, True));
ShowMessage(DateTimeToStr(d));
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Значение Unassigned
нужно иметь в виду при работе с Variant
. Но с практической точки зрения более интересно поведение в случае значения null
. Например, он часто встречается при получении значения из поля датасета (TField
) через свойство Value
.
Конвертация Null
Конвертация null
зависит от значения логической глобальной переменной System.Variants.NullStrictConvert
. Её значение по умолчанию равно True
и при попытке конвертации null
появляется исключение EVariantTypeCastError
. Если же значение NullStrictConvert
равно False
, то по умолчанию null
преобразуется аналогично Unassigned
.
procedure TForm1.Button1Click(Sender: TObject);
var
v: Variant;
i: Integer;
s: string;
b: Boolean;
d: TDateTime;
begin
NullStrictConvert := False;
v := null;
i := v; // 0
s := v; // пустая строка
b := v; // False
d := v; // 30.12.1899
ShowMessage(IntToStr(i));
ShowMessage(s);
ShowMessage(BoolToStr(b, True));
ShowMessage(DateTimeToStr(d));
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Есть особенность для типа String
. Можно задать какой строке будет равен null
. Например
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
s: string;
begin
NullStrictConvert := False;
NullAsStringValue := 'my_null';
v := null;
s := v;
ShowMessage(s); // my_null
end;
2
3
4
5
6
7
8
9
10
11
12
13
Выражения
Если null
участвует в выражении то результат выражения будет null
.
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
s: string;
begin
NullStrictConvert := False;
NullAsStringValue := 'null';
v := null + 2;
s := v;
ShowMessage(s); // null
end;
2
3
4
5
6
7
8
9
10
11
12
13
Ситуация с Unassigned
интереснее. Вероятно, срабатывает такое же преобразование как при конвертации, в данном примере к 0. Описания в документации нет.
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
s: string;
begin
v := v + 2;
s := v;
ShowMessage(s); // 2
end;
2
3
4
5
6
7
8
9
10
Сравнения
Поведение null
при сравнении зависит от глобальных переменных NullEqualityRule
и NullMagnitudeRule
.
NullEqualityRule
определяет результат операторов "=" и "<>" (равно и не равно). У этой переменной возможны три значения
ncrError
— сравнение сnull
вызывает исключениеncrStrict
— результат сравнение сnull
всегда равенFalse
ncrLoose
(по умолчанию) —null
равен другомуnull
и не равен другим значениям
procedure TForm1.Button1Click(Sender: TObject);
var
v: Variant;
flag: Boolean;
begin
v := null;
flag := v = null;
ShowMessage(BoolToStr(flag, True)); // True
end;
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
flag: Boolean;
begin
NullEqualityRule := ncrStrict;
v := null;
flag := v = null;
ShowMessage(BoolToStr(flag, True)); // False
end;
procedure TForm1.Button3Click(Sender: TObject);
var
v: Variant;
flag: Boolean;
begin
NullEqualityRule := ncrError;
v := null;
flag := v = null; // Исключение EVariantInvalidNullOpError
ShowMessage(BoolToStr(flag, True));
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
NullMagnitudeRule
определяет результат операторов "<" и ">" (больше и меньше). Значения этой переменной аналогичны NullEqualityRule
ncrError
— сравнение сnull
вызывает исключениеncrStrict
— результат сравнение сnull
всегда равенFalse
ncrLoose
(по умолчанию) —null
считается меньше любого другого значения
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
flag: Boolean;
begin
v := null;
flag := v < -1;
ShowMessage(BoolToStr(flag, True)); // True
end;
2
3
4
5
6
7
8
9
10
Интересный случай сравнения null с null
procedure TForm1.Button2Click(Sender: TObject);
var
v: Variant;
flag: Boolean;
begin
v := null;
flag := v < null;
ShowMessage(BoolToStr(flag, True)); // False
end;
2
3
4
5
6
7
8
9
10
Выводы
- Переменные типа
Variant
нужно всегда инициализировать, даже если они являются переменным класса, чтобы не сталкиваться сUnassigned
. - Во всех случаях при работе с
Variant
нужно учитыватьnull
. - Менять или не менять значение по умолчанию переменной
NullStrictConvert
вопрос открытый.
Ссылки
- Документацияopen in new window по типу Variant.