2011-11-08 39 views
11

在德爾福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

如何在MyRecord上重載In運算符,以便R in S在上面的代碼中將計算爲True

+1

我不認爲你想要達到的是可能的......你應該有更好的運氣寫一個額外的字符「.Value」=> BoolToStr(R.Value in S);並完成它 – ComputerSaysNo

+0

我的問題中的代碼只是一個簡化的示例。在我的實際應用中,記錄類型與集合類型沒有一對一的對應關係。我最終使用的解決方法是向記錄添加一個'函數InSet(S:MySet):Boolean',並使用它來代替'in'運算符。 –

+0

也許已經足夠讓會員功能,而不是 - BoolToStr(R._in(S));' –

回答

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在S)」。除非你正在爲每行代碼付費。並修復bug。

+0

這個特殊的問題只是一個練習來弄清楚我以前從未使用過的類操作符。我正在處理的實際代碼中的記錄類型要複雜得多。它定義的運算符允許使用該記錄的代碼更加簡單。幾百行簡單的運算符函數允許數千行復雜的代碼更具可讀性。 –

+0

對不起,我的評論有些諷刺。我承認我非常喜歡用新的操作符加載記錄,並廣泛使用它。我同意它在很多情況下使代碼更清晰。我只是在自己的解決方案上玩笑,因爲它在這種特殊情況下是矯枉過正;-) – HMcG

+0

「所以你的代碼中的R和S都必須是TMyRecord」,這是不正確的。 – Johan

5

對於in運算符來說,正確的操作數必須是記錄類型,因爲它是一個集合運算符而不是二元運算符。在你的情況下,它是左操作數。

所以下面的工作:

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;