将 null 分配给模拟的通用可为 null 的数据类型时出现问题
Problem assigning null to simulated generic nullable data types
我正在尝试在 Delphi 中创建可为 null 的数据类型:
type
TNullable<T> = record
public
Value: T;
IsNull: Boolean;
class operator Implicit(const AValue: T): TNullable<T>;
class operator Implicit(const AValue: TNullable<T>): T;
class operator Implicit(const AValue: Variant): TNullable<T>;
class operator Explicit(const AValue: T): TNullable<T>;
end;
到目前为止一切顺利,但是要将什么分配为 null
文字,以便可空数据类型保持其基本类型?例如:
var
v: TNullable<Integer>;
begin
//What type is this "null"? A Variant null?
//How TNullable<Integer> could remain of Integer after the assignment?
v := null;
//How to compare this "null"? Compare to what type?
if v = null then begin
end;
end;
让我们假设 null
是变体 null:
class operator TNullable<T>.Implicit(const AValue: Variant): TNullable<T>;
begin
if VarIsNull(AValue) or VarIsClear(AValue) then begin
Result.IsNull := True;
Result.Value := Default(T);
end
else begin
Result.IsNull := False;
Result.Value := AValue; //Version 1: Incompatible types: 'T' and 'Variant'!!!
Result.Value := T(AValue); //Version 2: Invalid typecast!!!
//Should I write a big "case" block here in order to handle each data type?!
end;
end;
你有什么想法吗?
Null
在这种情况下确实是 Variant
,参见 System.Variants.Null
。在这种情况下使用 Variant
不是一个好主意,部分原因是您遇到的分配问题。
更好的选择是定义一个不同的类型来表示您的 null
值(类似于 C++11 及更高版本中的 nullptr_t
),例如:
type
TNullValue = record
end;
TNullable<T{: record}> = record
public
Value: T;
HasValue: Boolean;
class operator Implicit(const AValue: T): TNullable<T>;
class operator Implicit(const AValue: TNullable<T>): T;
class operator Implicit(const AValue: TNullValue): TNullable<T>;
class operator Explicit(const AValue: T): TNullable<T>;
// add these...
class operator Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
class operator NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
...
end;
const
NullValue: TNullValue;
...
class operator TNullable<T>.Implicit(const AValue: T): TNullable<T>;
begin
Result.Value := AValue;
Result.HasValue := True;
end;
class operator TNullable<T>.Implicit(const AValue: TNullable<T>): T;
begin
if AValue.HasValue then
Result := AValue.Value
else
Result := Default(T); // or raise an exception
end;
class operator TNullable<T>.Implicit(const AValue: TNullValue): TNullable<T>;
begin
Result.Value := Default(T);
Result.HasValue := False;
end;
class operator TNullable<T>.Explicit(const AValue: T): TNullable<T>;
begin
Result.Value := AValue;
Result.HasValue := True;
end;
class operator TNullable<T>.Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
Result := not A.HasValue;
end;
class operator TNullable<T>.NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
Result := A.HasValue;
end;
var
v: TNullable<Integer>;
begin
v := NullValue;
if v = NullValue then begin
...
end;
if v <> NullValue then begin
...
end;
end;
我正在尝试在 Delphi 中创建可为 null 的数据类型:
type
TNullable<T> = record
public
Value: T;
IsNull: Boolean;
class operator Implicit(const AValue: T): TNullable<T>;
class operator Implicit(const AValue: TNullable<T>): T;
class operator Implicit(const AValue: Variant): TNullable<T>;
class operator Explicit(const AValue: T): TNullable<T>;
end;
到目前为止一切顺利,但是要将什么分配为 null
文字,以便可空数据类型保持其基本类型?例如:
var
v: TNullable<Integer>;
begin
//What type is this "null"? A Variant null?
//How TNullable<Integer> could remain of Integer after the assignment?
v := null;
//How to compare this "null"? Compare to what type?
if v = null then begin
end;
end;
让我们假设 null
是变体 null:
class operator TNullable<T>.Implicit(const AValue: Variant): TNullable<T>;
begin
if VarIsNull(AValue) or VarIsClear(AValue) then begin
Result.IsNull := True;
Result.Value := Default(T);
end
else begin
Result.IsNull := False;
Result.Value := AValue; //Version 1: Incompatible types: 'T' and 'Variant'!!!
Result.Value := T(AValue); //Version 2: Invalid typecast!!!
//Should I write a big "case" block here in order to handle each data type?!
end;
end;
你有什么想法吗?
Null
在这种情况下确实是 Variant
,参见 System.Variants.Null
。在这种情况下使用 Variant
不是一个好主意,部分原因是您遇到的分配问题。
更好的选择是定义一个不同的类型来表示您的 null
值(类似于 C++11 及更高版本中的 nullptr_t
),例如:
type
TNullValue = record
end;
TNullable<T{: record}> = record
public
Value: T;
HasValue: Boolean;
class operator Implicit(const AValue: T): TNullable<T>;
class operator Implicit(const AValue: TNullable<T>): T;
class operator Implicit(const AValue: TNullValue): TNullable<T>;
class operator Explicit(const AValue: T): TNullable<T>;
// add these...
class operator Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
class operator NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
...
end;
const
NullValue: TNullValue;
...
class operator TNullable<T>.Implicit(const AValue: T): TNullable<T>;
begin
Result.Value := AValue;
Result.HasValue := True;
end;
class operator TNullable<T>.Implicit(const AValue: TNullable<T>): T;
begin
if AValue.HasValue then
Result := AValue.Value
else
Result := Default(T); // or raise an exception
end;
class operator TNullable<T>.Implicit(const AValue: TNullValue): TNullable<T>;
begin
Result.Value := Default(T);
Result.HasValue := False;
end;
class operator TNullable<T>.Explicit(const AValue: T): TNullable<T>;
begin
Result.Value := AValue;
Result.HasValue := True;
end;
class operator TNullable<T>.Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
Result := not A.HasValue;
end;
class operator TNullable<T>.NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
Result := A.HasValue;
end;
var
v: TNullable<Integer>;
begin
v := NullValue;
if v = NullValue then begin
...
end;
if v <> NullValue then begin
...
end;
end;