Delphi'in'运算符在一组上重载

时间:2011-11-08 03:33:04

标签: delphi operator-overloading delphi-xe2

在Delphi XE2中,我试图重载记录上的in运算符,以允许我检查记录所代表的值是否是集合的一部分。我的代码如下所示:

type
  MyEnum = (value1, value2, value3);
  MySet = set of MyEnum;
  MyRecord = record
    Value: MyEnum;
    class operator In(const A: MyRecord; B: MySet): Boolean;
  end;

class operator MyRecord.In(const A: MyRecord; B: MySet): Boolean;
begin
  Result := A.Value in B;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  R: MyRecord;
  S: MySet;
begin
  R.Value := value1;
  S := [value1, value2];
  Button1.Caption := BoolToStr(R in S);
end;

代码无法编译。对于语句R in S,编译器说:不兼容的类型MyRecordMyEnum

如何在In上重载MyRecord运算符,以便R in S在上面的代码中评估为True

2 个答案:

答案 0 :(得分:5)

要使in运算符工作,右操作数必须是记录类型,因为它是set运算符而不是二元运算符。在你的情况下,它是左操作数。

以下内容将起作用:

type
  MyRecord = record
    Value: MyEnum;
    class operator In(const A: MyRecord; const B: MySet): Boolean;
  end;

  MyRecord2 = record
    Value: MySet;
    class operator In(const A: MyRecord; const B: MyRecord2): Boolean;
    class operator In(const A: MyEnum; const B: MyRecord2): Boolean;
  end;

class operator MyRecord.In(const A: MyRecord; const B: MySet): Boolean;
begin
  Result := A.Value in B;
end;

class operator MyRecord2.In(const A: MyRecord; const B: MyRecord2): Boolean;
begin
  Result := A.Value in B.Value;
end;

class operator MyRecord2.In(const A: MyEnum; const B: MyRecord2): Boolean;
begin
  Result := A in B.Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  R: MyRecord;
  R2: MyRecord2;
begin
  R.Value := value1;
  R2.Value := [value1, value2];

  if R in R2 then;
  if value1 in R2 then;
end;

答案 1 :(得分:1)

嗯,你可以差不多这样做,但你可能不想这样做。 AFAIK,类操作符只能处理它们所定义的类(或记录),因此代码中的R和S都必须是TMyRecord。通过隐式转换的一些不明智的使用,我们得到以下结果:

unit Unit2;
interface
type
  MyEnum = (value1, value2, value3);
  MySet = set of MyEnum;
  MyRecord = record
    Value: MyEnum;
    ValueSet: MySet;
    class operator Implicit(A: MyEnum): MyRecord;
    class operator Implicit(A: MySet): MyRecord;
    class operator In (Left,Right:MyRecord): Boolean;
  end;

implementation

class operator MyRecord.Implicit(A: MyEnum): MyRecord;
begin
  Result.Value := A;
end;

class operator MyRecord.Implicit(A: MySet): MyRecord;
begin
  Result.ValueSet := A;
end;

class operator MyRecord.In(Left, Right: MyRecord): Boolean;
begin
  Result:= left.Value in Right.ValueSet;
end;
end.

以下内容现在可以完成,甚至可以工作:

procedure TForm1.Button1Click(Sender: TObject);
var
  R: MyRecord;
  S: MyRecord;
begin
  R.Value := value1;
  S := [value1,value2,value3];
  Button1.Caption := BoolToStr(R In S,true);
end;

其中,我相信大家都会同意,比'BoolToStr(R.Value in S)'更优雅。 但是,以下内容也会编译,但结果错误:

procedure TForm1.Button1Click(Sender: TObject);
var
  R: MyRecord;
  S: MyRecord;
begin
  R.Value := value1;
  S := [value1,value2,value3];
  Button1.Caption := BoolToStr(S In R,true);
end;

所以,正如Dorin评论的那样,更好的是只有沉闷,沉稳的老'BoolToStr(R.Value in S)'。除非您按行代码付费。修复错误也是一个奖励。