Một tùy chọn khác (nếu bạn có phiên bản tương đối hiện đại cho Delphi) là triển khai bản ghi này dưới dạng bản ghi, với chuyển đổi ngầm đến và từ giá trị boolean. Với quá tải toán tử, bạn cũng có thể kích hoạt logic 3 trạng thái. Đây là quá mức cần thiết nếu tất cả những gì bạn yêu cầu thỉnh thoảng sử dụng, nhưng nếu bạn cần hệ thống logic ba trạng thái, nó hoạt động rất độc đáo, đặc biệt khi bạn có thể gán các giá trị boolean cho nó. Hãy cẩn thận với các bài tập từ suy nghĩ từ 3 tiểu bang đến 2 tiểu bang. Ví dụ dưới đây gán False cho Boolean < - sự phân công 'Troolean' nơi troolean là TNil, theo một boolean chưa được gán trong Delphi, nhưng có những biến chứng rõ ràng.
Xin lưu ý rằng đây không phải là cách triển khai hoàn chỉnh hoặc hiệu quả bằng bất kỳ phương tiện nào, đó chỉ là bản trình diễn để xác định những gì có thể. Ngẫu nhiên, có một CodeRage vidoe tốt bởi Jeroen Pluimers trên các kiểu nullable. Câu hỏi This cung cấp liên kết.
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.
Và một ví dụ về sử dụng
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 Đây là cách tốt nhất để đạt được điều này, IMO. Có ba trạng thái: 'doSomething (1)', 'doSomething (1, True)' và 'doSomething (1, False)'. –
@Rudy, vâng, nhưng chỉ vì OP xác định cần phải làm việc với các tham số * Boolean *. Nếu không, tôi nghĩ rằng 3 đường dẫn mã riêng biệt được phân biệt hiệu quả hơn bằng cách sử dụng một biến trạng thái 3 (ví dụ như ví dụ ThreeStateBoolean của Greg Hewgill). – Sam
@Rudy, điều này làm cho câu trả lời tốt hơn là nó tuân theo câu của OP "đôi khi chúng ta muốn tham số tùy chọn", không phải là ba trạng thái được hỗ trợ (vì cả hai câu trả lời đều làm như vậy). IMO. – Sam