2012-01-23 24 views
5

Dado el siguiente fragmento de código:TCustomAttribute - "expresión constante espera" Error de compilación

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; 

¿Por qué el compilador que esto no es una expresión constante? Pero dado que uso InvisiblePropInterfaces como este, ¿el compilador está feliz?

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

Respuesta

6

La sección pertinente de la attributes documentation es la siguiente:

Es importante entender que los valores pasados ​​al constructor del atributo deben ser expresiones constantes. Como esos valores se deben incrustar directamente en el binario resultante, es imposible pasar una expresión que requiera una evaluación en tiempo de ejecución. Esto plantea algunas limitaciones a la información que se puede pasar al atributo en tiempo de compilación: Se permiten

  • expresiones Sólo constantes, incluyendo conjuntos, cadenas y expresiones ordinales.
  • no se pueden utilizar los parámetros out y var, ya que requieren una evaluación en tiempo de ejecución de las direcciones de los parámetros pasados.
  • Addr() no se puede usar el operador intrínseco @.
  • El operador TypeInfo() se puede utilizar para pasar información de tipo, porque las direcciones del bloque RTTI se conocen en tiempo de compilación.
  • Las referencias de clase están permitidas, porque las direcciones de metaclase (como el caso de TypeInfo()) se conocen en tiempo de compilación.

El punto clave es que un constant expression es un término técnico que Pascal no es lo mismo que una constante. Sospecho que esta es la raíz de la confusión.

Dado que no es posible tener una expresión constante que se pueda pasar a TGUID, no tiene suerte con su atributo. De hecho, es igual de imposible tener una expresión constante que pueda pasarse a un parámetro de matriz abierta.

Supongo que puede utilizar la representación de cadena del GUID para resolver el enigma, pero eso le dejará con la duplicación desordenada y la imposibilidad de pasar matrices de GUID.

+0

parece que no he tenido suerte con mi primer uso real de los atributos. Bueno, entonces tengo que cambiar mi diseño y simplemente decorar mis clases con otra interfaz, algo así como: IInvisiblePropInterfaces = función de interfaz GetGuids: array of TGuid – iamjoosy

-2

Em porque usted le dijo que esperar un

TInvisiblePropInterfaces.Create (const GUID: conjunto de TGUID);

Su atributo sabe absolutamente nada de MyIntf

+1

el compilador puede recuperar un GUID desde un tipo de interfaz, por lo que es absolutamente legal dar un tipo de interfaz (dado que tiene un GUID) cuando se espera un tipo de TGUID. Ver también mi pregunta editada. – iamjoosy

+0

No se esperaba * que el atributo * supiera nada acerca de la interfaz, * aún *. Es por eso que se proporciona como un parámetro. Y su lógica no tiene sentido: ¿el compilador se queja de que algo * no es * una expresión constante porque le dijimos que esperara una?Incluso si la declaración * no * le indicó al compilador que esperara una expresión constante (no lo hace), simplemente decirle al compilador que espere uno no es motivo suficiente para que nos diga que algo * no es * uno. La pregunta se pregunta por qué el compilador cree que la expresión dada no es constante, no por qué el compilador espera una expresión constante. –

+0

Lo siento, me has perdido. "Por qué el comiler piensa que no es una constante". ¿Adivinar suerte ?, generador de números aleatorios, llamó a un amigo, o puede ser, simplemente puede ser, en algún lugar, alguien dijo que no era uno ... –

1

Ésta es una limitación conocida. TGUID se declara como un tipo de registro y no hay forma de hacer una expresión constante de grabación.

+1

no es cierto. Simplemente puede llamar a InvisiblePropInterfaces.Create ([MyIntf]) sin problemas. Parece que en su contexto de atributo no compila. – iamjoosy

+1

Cuando lo llamas manualmente, ya no tiene que ser una expresión constante. –

+0

@Rob, pero ¿([MyIntf]) no es una expresión constante? – iamjoosy

Cuestiones relacionadas