Delphi 'in' перегрузка оператора на множестве
В 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
компилятор говорит: Несовместимые типы MyRecord
и MyEnum
.
Как я могу перегрузить оператор in
на MyRecord
, чтобы R in S
оценил значение True
в приведенном выше коде?
Ответы
Ответ 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;
Итак, как прокомментировал Дорин, лучше просто иметь скучный, старомодный старый "BoolToStr" (R.Value in S) ". Если, конечно, вам не платят за строку кода. И бонус для исправления ошибок.
Ответ 2
Для того чтобы оператор 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;