如何解决将null分配给模拟的通用nullable数据类型时出现问题
我正在尝试在Delphi中创建可为空的数据类型:
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;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。