14

Delphi で3 つの値を持つロジックを最適に実装するにはどうすればよいですか?

考えていた

type
  TExtBoolean = (ebTrue, ebFalse, ebUnknown);

function ExtOr(A: TExtBoolean; B: TExtBoolean): TExtBoolean;
begin
  if (A = ebTrue) or (B = ebTrue) then
    Result := ebTrue
  else if (A = ebFalse) and (B = ebFalse) then
    Result := ebFalse
  else
    Result := ebUnknown;
end;

等々。

しかし、それはあまりエレガントではないようです。より良い方法はありますか?

編集:エレガンスとは、使いやすいことを意味します。実装が洗練されているほど、優れています。CPU 効率は、私にとって (それほど) 重要ではありません。

4

2 に答える 2

5

なので。ここでエレガンクルとはどういう意味ですか? 実装のエレガンス、使用のエレガンス、CPI の効率性、保守性 ? エレガンスはとても曖昧な言葉です...

のような流儀で使える型に変換するのが、使いやすくするための当然の方法だと思いますExtBoolean1 or (ExtBoolean2 and True)

ただし、必要な機能は、Delphi 2006 (それ自体はかなりバグのあるリリース) よりも前かそれより前のバージョンである可能性があるためDUnit、多くのテストを行ってください..

使用する機能とその説明を一覧表示するには:

  1. 拡張レコード:クラスの代わりに Delphi で拡張レコード タイプを使用する必要があるのはいつですか? およびhttp://delphi.about.com/od/adptips2006/qt/newdelphirecord.htmおよびマニュアル
  2. 暗黙的な型キャストを含む操作のオーバーロード: 「拡張レコード」を通常の「データ型」変数に割り当てるときに、どの演算子をオーバーロードしますか? およびDelphiマニュアルでの演算子のオーバーロード
  3. 関数のインライン化: Delphiとマニュアルでの inline キーワードの使用とは

これらのアイデアのいくつかを概説するには:

type
  TExtBoolean = record
     Value: (ebUnknown, ebTrue, ebFalse);

     function IsNull: boolean; inline;
     function Defined: boolean; inline;

     class operator Implicit ( from: boolean ): TExtBoolean; inline;
     class operator Implicit ( from: TExtBoolean ): boolean; 
     class operator LogicalAnd( Value1, Value2: TExtBoolean ):   TExtBoolean; 
     class operator LogicalAnd( Value1: TExtBoolean; Value2: boolean):  TExtBoolean; inline;
     class operator LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
....
  end;

const Unknown: TExtBoolean = (Value: ebUnknown); 

...
var v1: TExtBoolean;
    v1 := False; 
    v1 := True;
    v1 := Unknown;
...

class operator TExtBoolean.Implicit ( from: boolean ): TExtBoolean; 
begin
  if from
     then Result.Value := ebTrue
     else Result.Value := ebFalse
end;

class operator TExtBoolean.Implicit ( from: TExtBoolean ): Boolean; 
begin
  case from.Value of
    ebTrue: Result := True;
    ebFalse: Result := False;  
    else raise EConvertError.Create('....');
end;


function TExtBoolean.Defined: boolean; 
begin
  Result := (Self.Value = ebTrue) or (Self.Value = ebFalse);
end;

// this implementation detects values other than ebTrue/ebFalse/ebUnkonwn
// that might appear in reality due to non-initialized memory garbage 
// since hardware type of Value is byte and may be equal to 3, 4, ...255
function TExtBoolean.IsNull: boolean; 
begin
  Result := not Self.Defined
end;

class operator TExtBoolean.And( Value1, Value2: TExtBoolean ): TExtBoolean; 
begin
  if Value1.IsNull or Value2.IsNull
     then Result.Value := eb.Undefined
     else Result := boolean(Value1) and boolean(Value2);
// Or, sacrificing readability and safety for the sake of speed
// and removing duplicate IsNull checks
//   else Result := (Value1.Value = ebTrue) and (Value2.Value = ebTrue);
end;

class operator TExtBoolean.LogicalAnd( Value1, TExtBoolean; Value2: boolean):  TExtBoolean;
begin
  Result := Value2 and Value1;
end;

class operator TExtBoolean.LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
begin
  if Value2.IsNull
     then Result := Value2
     else Result := Value1 and (Value2.Value = ebTrue);
// or if to accept a duplicate redundant check for readability sake
//   and to avert potential later erros (refactoring, you may accidentally remove the check above)
//    else Result := Value1 and boolean (Value2);
end;

PS。上記の未指定のチェックは、意図的に悲観的になり、悪い方向に進む傾向があります。これは、初期化されていない変数と将来の変更の可能性に対する防御であり、3 つ以上の状態を追加します。これは過剰に保護しているように見えるかもしれませんが、少なくとも Delphi XE2 は mee に同意しています: 同様のケースの警告を参照してください:

program Project20;  {$APPTYPE CONSOLE}
uses System.SysUtils;

type enum = (e1, e2, e3);
var e: enum;

function name( e: enum ): char;
begin
  case e of
    e1: Result := 'A';
    e2: Result := 'B';
    e3: Result := 'C';
  end;
end;

// [DCC Warning] Project20.dpr: W1035 Return value of function 'name' might be undefined

begin
  for e := e1 to e3
      do Writeln(name(e));
  ReadLn;
end.
于 2013-10-23T08:36:43.313 に答える