2012-01-23 82 views
5

考慮下面的代碼片段:TCustomAttribute - 「常量表達式預期」編譯錯誤

type 
    MyIntf = interface 
    ['{C6184693-663E-419F-B2DA-4DA1A0E33417}'] 
    procedure Foo; 
    end; 

    InvisiblePropInterfaces = class(TCustomAttribute) 
    private 
    FGUIDS: array of TGUID; 
    public 
    constructor Create(const GUIDS: array of TGUID); 
    end; 

    [InvisiblePropInterfaces([MyIntf])] // <-- Constant expression expected error 
    TMyClass = class(TInterfacedObject, MyIntf) 
    procedure Foo; 
    end; 

爲什麼編譯器認爲這不是一個常量表達式? 但是,鑑於我使用InvisiblePropInterfaces這樣,編譯器只是快樂?

... 
var 
    I: InvisiblePropInterfaces; 
begin 
    I:= InvisiblePropInterfaces.Create([MyIntf]); 
... 

回答

6

attributes documentation的有關章節是這樣的:

理解傳遞給屬性的構造函數值必須是常量表達式是很重要的。由於這些值必須直接嵌入到生成的二進制文件中,因此不可能傳遞需要運行時評估的表達式。這對編譯時可傳遞給屬性的信息提出了一些限制:

  • 只允許使用常量表達式,包括集合,字符串和有序表達式。
  • out和var參數不能使用,因爲它們需要運行時評估傳遞參數的地址。
  • Addr()內部和@操作符不能使用。
  • TypeInfo()運算符可用於傳遞類型信息,因爲RTTI塊地址在編譯時已知。
  • 允許類引用,因爲元類地址(如TypeInfo()的情況)在編譯時已知。

關鍵的一點是,constant expression是一個技術術語帕斯卡爾是不一樣的事,作爲一個常數。我懷疑這是混亂的根源。

由於不可能有一個可以傳遞給TGUID的常量表達式,因此您的屬性運氣不佳。事實上,擁有一個可以傳遞給開放數組參數的常量表達式是不可能的。

我想你可以使用GUID的字符串表示來解決這個難題,但這會給你帶來混亂的重複和無法傳遞GUID數組。

+0

似乎我運氣不佳,首次真正使用屬性。那麼,我不得不改變我的設計,只是用另一個接口來修飾我的類,如下所示:IInvisiblePropInterfaces =接口函數GetGuids:TGuid數組 – iamjoosy

-2

嗯,因爲你告訴它期待一個

TInvisiblePropInterfaces.Create(常量GUIDS:TGUID數組);

你的屬性知道絕對沒有關於MyIntf

+1

編譯器可以從接口類型中檢索一個GUID,所以在預期TGUID類型時給出一個接口類型(假定它有一個GUID)是絕對合法的。另見我編輯的問題。 – iamjoosy

+0

該屬性不是*預期*知道接口的任何內容,* yet *。這就是它作爲參數提供的原因。而你的邏輯沒有意義:編譯器抱怨說,*不是一個常量表達式,因爲我們告訴它期望一個?即使聲明*告訴編譯器期望一個常量表達式(它沒有),僅僅告訴編譯器期望一個不足以告訴我們某個*不是一個*的理由。這個問題問爲什麼編譯器認爲給定的表達式不是常量,而不是爲什麼編譯器需要一個常量表達式。 –

+0

對不起,你失去了我。 「爲什麼這個comiler認爲它不是一個常量」。幸運的猜測?,隨機數字生成器,打電話給朋友,或者可能,可能只是某個地方有人告訴它不是一個...... –

1

這是一個已知的限制。 TGUID被聲明爲記錄類型,並且沒有辦法記錄常量表達式。

+1

不正確。你可以直接調用InvisiblePropInterfaces.Create([MyIntf])。看來在它的屬性上下文中它不能編譯。 – iamjoosy

+1

當你手動調用它時,它不再是一個常量表達式。 –

+0

@Rob,但是([MyIntf])不是一個常量表達式? – iamjoosy