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

Jan*_*rts 11 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;
Run Code Online (Sandbox Code Playgroud)

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

如何重载In运算符,MyRecord以便在上面的代码中R in S进行求值True

Ste*_*nke 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;
Run Code Online (Sandbox Code Playgroud)


HMc*_*McG 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.
Run Code Online (Sandbox Code Playgroud)

以下内容现在将编译,甚至可以工作:

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;
Run Code Online (Sandbox Code Playgroud)

我相信我们都会同意,它比“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;
Run Code Online (Sandbox Code Playgroud)

因此,正如 Dorin 评论的那样,最好还是使用沉闷、古板的“BoolToStr(R.Value in S)”。当然,除非您按行代码付费。以及修复错误的奖励。