Otra opción (si tiene una versión relativamente moderna de Delphi) es implementar esto como un registro, con conversión implícita hacia y desde valores booleanos. Con la sobrecarga del operador, también puede habilitar la lógica de 3 estados. Esto es exagerado si todo lo que necesita es un uso ocasional, pero si necesita un sistema lógico de tres estados, funciona muy bien, sobre todo porque le puede asignar valores booleanos. Tenga cuidado con las asignaciones del pensamiento de 3 estados a 2 estados. El siguiente ejemplo asigna False a un booleano < - Asignación 'Troolean' donde el troolean es TNil, según un booleano no asignado en Delphi, pero hay complicaciones obvias.
Tenga en cuenta que esta no es una implementación completa o eficiente de ninguna manera, es solo una demostración para indicar lo que es posible. Incidentalmente, hay un buen Codevy vidoe por Jeroen Pluimer en tipos anulables. This pregunta proporciona un enlace.
unit UnitTroolean;
interface
type
TTroolean = record
private type
TThreeState = (TTrue = 1, TFalse = 0, TNil = -1);
var
fThreeState: TThreeState;
public
function AsString: string;
class operator Implicit(Value: boolean): TTroolean;
class operator Implicit(Value: TTroolean): boolean;
class operator Implicit(Value: TThreeState): TTroolean;
class operator Implicit(Value: TTroolean): TThreeState;
class operator LogicalAnd(Left, Right: TTroolean): TTroolean;
class operator LogicalOr(Left, Right: TTroolean): TTroolean;
class operator LogicalNot(Value: TTroolean): TTroolean;
end;
implementation
{ TRoolean }
class operator TTroolean.Implicit(Value: boolean): TTroolean;
begin
if Value then
result.fThreeState := TTrue
else
result.fThreeState := TFalse;
end;
class operator TTroolean.Implicit(Value: TTroolean): boolean;
begin
if not(Value.fThreeState = TNil) then
result := (Value.fThreeState = TTrue)
else
result := false;
end;
class operator TTroolean.Implicit(Value: TThreeState): TTroolean;
begin
result.fThreeState := Value;
end;
class operator TTroolean.Implicit(Value: TTroolean): TThreeState;
begin
result := Value.fThreeState;
end;
class operator TTroolean.LogicalAnd(Left, Right: TTroolean): TTroolean;
begin
if (Left.fThreeState = TNil) or (Right.fThreeState = TNil) then
result.fThreeState := TNil
else if ((Left.fThreeState = TTrue) and (Right.fThreeState = TTrue)) then
result.fThreeState := TTrue
else
result.fThreeState := TFalse;
end;
class operator TTroolean.LogicalNot(Value: TTroolean): TTroolean;
begin
begin
case value.fThreeState of
TNil: result.fThreeState:= TNil;
TTrue: result.fThreeState:= TFalse;
TFalse: result.fThreeState:= TTrue
end;
end;
end;
class operator TTroolean.LogicalOr(Left, Right: TTroolean): TTroolean;
begin
if (Left.fThreeState = TNil) or (Right.fThreeState = TNil) then
result.fThreeState := TNil
else if ((Left.fThreeState = TTrue) or (Right.fThreeState = TTrue)) then
result.fThreeState := TTrue
else
result.fThreeState := TFalse;
end;
function TTroolean.AsString: string;
begin
case ord(fThreeState) of
1:
result := 'TTrue';
0:
result := 'TFalse';
-1:
result := 'TNil';
end;
end;
end.
Y un ejemplo de uso
program ThreeStateLogicTest;
{$APPTYPE CONSOLE}
uses
SysUtils,
UnitTroolean in 'UnitTroolean.pas';
var
ABoolean: boolean;
ATroolean, Anothertroolean, AThirdTroolean: TTroolean;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write(#10#13);
ATroolean := TFalse;
ABoolean := true;
ATroolean := ABoolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ATroolean := TTrue;
ABoolean := false;
ATroolean := ABoolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ABoolean := false;
ATroolean := TTrue;
ABoolean := ATroolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ABoolean := true;
ATroolean := TFalse;
ABoolean := ATroolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ABoolean := false;
ATroolean := Tnil;
ABoolean := ATroolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ABoolean := true;
ATroolean := Tnil;
ABoolean := ATroolean;
write('Boolean:', BoolToStr(ABoolean, true), #10#13);
write('Troolean:', ATroolean.AsString, #10#13);
write('Troolean as Boolean:', BoolToStr(ATroolean, true), #10#13);
write(#10#13);
ATroolean := TTrue;
Anothertroolean := false;
AThirdTroolean := ATroolean and Anothertroolean;
write('And:', AThirdTroolean.AsString, #10#13);
AThirdTroolean := ATroolean or Anothertroolean;
write('Or:', AThirdTroolean.AsString, #10#13);
ATroolean := TNil;
Anothertroolean:= not ATroolean;
write('Not TNil:', Anothertroolean.AsString, #10#13);
ATroolean := TTrue;
Anothertroolean:= not ATroolean;
write('Not Ttrue:', Anothertroolean.AsString, #10#13);
ATroolean := Tfalse;
Anothertroolean:= not ATroolean;
write('Not Tfalse:', Anothertroolean.AsString, #10#13);
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
+1 Esta es la mejor manera de lograr esto, IMO. Hay tres estados: 'doSomething (1)', 'doSomething (1, True)' y 'doSomething (1, False)'. –
@Rudy, sí, pero solo porque el OP especificó la necesidad de trabajar con los parámetros * Boolean *. De lo contrario, creo que 3 rutas de código distintas se diferencian más eficientemente mediante el uso de una única variable de estado 3 (como el ejemplo ThreeStateBoolean de Greg Hewgill). – Sam
@Rudy, lo que hace que esta sea la mejor respuesta es que cumple con la frase de OP "a veces queremos un parámetro opcional", no el hecho de que tres estados sean compatibles (porque ambas respuestas lo hacen). IMO. – Sam