Criei um tipo anulável como este, que encontrei em uma resposta do SO, não lembro qual.
unit NullableType;
interface
uses
System.SysUtils, System.Rtti;
type
TNullable<T> = record
private
FValue: T;
FHasValue: IInterface;
function GetHasValue: Boolean;
function GetValue: T;
procedure SetValue(const AValue: T);
public
constructor Create(AValue: T);
function ToString: string; // <-- add this for easier use!
property HasValue: Boolean read GetHasValue;
property Value: T read GetValue write SetValue;
end;
implementation
constructor TNullable<T>.Create(AValue: T);
begin
SetValue(AValue);
end;
function TNullable<T>.GetHasValue: Boolean;
begin
Result := FHasValue <> nil;
end;
function TNullable<T>.GetValue: T;
begin
if HasValue then
Result := FValue
else
Result := Default(T);
end;
procedure TNullable<T>.SetValue(const AValue: T);
begin
FValue := AValue;
FHasValue := TInterfacedObject.Create;
end;
function TNullable<T>.ToString: string;
begin
if HasValue then
begin
if TypeInfo(T) = TypeInfo(TDateTime) then
Result := DateTimeToStr(PDateTime(@FValue)^)
else if TypeInfo(T) = TypeInfo(TDate) then
Result := DateToStr(PDateTime(@FValue)^)
else if TypeInfo(T) = TypeInfo(TTime) then
Result := TimeToStr(PDateTime(@FValue)^)
else
Result := TValue.From<T>(FValue).ToString;
end
else
Result := 'null';
end;
end.
Meu problema é que não sei como defini-lo como nulo.
Por exemplo
var
id : TNullable<integer>;
begin
if Edit1.Text <> '' then
id.Value := StrToInt(Edit1.Text)
else
id.Value := null; // runtime error
isso me dá erro de tempo de execução
Não foi possível converter a variante do tipo (Null) em tipo (Integer)
Já faz um tempo que programo em Delphi e não consigo descobrir como definir o valor da id
variável paranull
id.Value := nil;
dá erro de compilador
Tipos incompatíveis: 'integer' e 'pointer'
Somente não definindo o valor de id
eu consigo ter seu valor null
, mas e se eu quiser defini-lo para qualquer valor, incluindo null? Como fazer isso?
null
é um constVariant
do tipoVT_NULL
, é por isso que você está recebendo um erro de tempo de execução relacionado a umaVariant
conversão. Você quernil
em vez disso.No entanto, você não pode atribuir a
nil
para aT
quandoT
não for um tipo de ponteiro. Então, para fazer o que você quer, você precisa atualizarNullable<T>
para aceitarT^
ponteiros como entrada.Do Delphi 2006 em diante, um
record
pode sobrecarregar operadores , então você não precisa aceitar atribuições por meio de umaValue
propriedade. Você pode sobrecarregar operadores de conversão que permitirão que você convertaT
valores eT^
ponteiros emNullable<T>
(e convertaNullable<T>
emT
valores), então você poderá atribuirnil
ponteiros para suasNullable
variáveis, por exemplo:Além disso, a partir do Delphi 10.4, você pode usar um Custom Managed Record para substituir o
IInterface
por um simplesBoolean
, por exemplo:IInterface
é baseado em um antigo artigo de blog escrito por Allen Bauer que antecede a introdução dos CMRs. Ele até afirma no artigo que os CMRs teriam resolvido o problema que ele estava usandoIInterface
como solução alternativa!Se você precisar dar suporte a versões mais antigas do Delphi, basta
IFDEF
codificar adequadamente.Já que você usa uma interface para detectar se tem um valor ou não, eu faria isso:
Você não pode fazer isso por atribuição (ou talvez você possa - declarar um operador de atribuição que aceite um valor de ponteiro, mas permita apenas
NIL
como valor, e então chamarSetNull
. Se você tentar atribuir um nãoNIL
ponteiro, gere uma exceção).