もう1つのオプション(Delphiの最新のバージョンを使用している場合)は、これをレコードとして実装し、ブール値との間の暗黙的な変換を行います。演算子のオーバーロードによって、3ステートロジックを有効にすることもできます。 あなたが必要とするものが時々使用されるのなら、これは過剰ですが、3状態のロジックシステムが必要な場合は、特にブール値を割り当てることができるので、非常にうまく動作します。 スリーステートから2-ステートへの割り当てに注意してください。以下の例では、FALSEをブール値<に割り当てています.Trooleanは、Delphiの割り当てられていないブール値のようにTNilであり、明らかな複雑さがあります。
これは完全にまたは効率的な実装ではありませんが、可能なことを告げるデモです。ちなみに、null可能な型のJeroen PluimersによるよいCodeRage vidoeがあります。 This質問にはリンクがあります。
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.
および使用
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これを達成するための最良の方法は、IMOです。 'doSomething(1)'、 'doSomething(1、True)'、 'doSomething(1、False)'の3つの状態があります。 –
@Rudy、はい、しかしOPが*ブール*パラメータで作業する必要があることを指定したからです。さもなければ、3つの異なるコードパスが、単一の3つの状態変数(Greg HewgillのThreeStateBooleanの例など)を使用することによって、より効率的に区別されると思います。 – Sam
@Rudy、これはより良い答えになるのは、OPの文に「時にはオプションのパラメータが必要です」ということです.3つの状態がサポートされているわけではありません。 IMO。 – Sam