2009-09-14 15 views
16

He declarado el siguiente tipo de enumeración en el que quiero que el primer miembro tenga el valor ordinal de 1 (uno) en lugar del 0 habitual (cero) :¿Por qué obtengo el error "type no tiene typeinfo" con un enumeración tipo

type 
    TMyEnum = (
       meFirstValue = 1, 
       meSecondValue, 
       meThirdValue 
      ); 

Si llamo TypeInfo(), por ejemplo, como parte de una llamada a GetEnumName(), me sale un error de compilación:

GetEnumName(TypeInfo(TMyEnum), Ord(aValue)); 

ERROR: "E2134 comercio: Tipo 'TMyEnum' no tiene typeinfo"

¿Por qué es esto?

sé que las clases sólo tienen typeinfo si se compilan con la opción compilador $ M habilitado o (derivarse de alguna clase que era, como TPersistent), pero no pensé que había alguna condición especial por tener typeinfo para tipos enum.

Respuesta

18

La información de tipo no se admite en enumeraciones en las que se asignan valores ordinales específicos que dan como resultado miembros enum que tienen valores ordinales que son diferentes a los que normalmente asignaría el compilador.

Si los valores específicos son esenciales o deseables, los miembros enum "sin usar" deberán insertarse para "rellenar" la enumeración según sea necesario. por ejemplo (sangría adicional para dar énfasis solamente):

type 
    TMyEnum = (
       meNOTUSED1, {= 0} 
       meFirstValue, {= 1} 
       meSecondValue, 
       meThirdValue 
      ); 

un subrango se puede utilizar para "filtrar" el valor inicial no utilizada:

TValidMyEnum = meFirstValue..meThirdValue; 

A pesar de que entonces puede ser que desee considerar la posibilidad de cambiar el nombre de la enumeración original, escriba para que su tipo de subrango se pueda usar a lo largo de su proyecto.

un subrango no es suficiente si la enumeración contiene "huecos":

type 
    TMyEnum = (
       meNOTUSED1, {= 0} 
       meFirstValue, {= 1} 
       meSecondValue, 
       meThirdValue, 
       meNOTUSED2, 
       meFinalValue {= 5} 
      ); 

En este caso no hay una forma sencilla de extender el rango en tiempo de compilación para excluir a los miembros no utilizados, pero un par de establecer tipos simplificarán el negocio de implementar cualquier tiempo de ejecución necesario comprobaciones:

type 
    TMyEnums = set of TMyEnum; 

    const 
    meNOTUSED  = [meUNUSED1, meUNUSED2]; // .. etc as required 
    meValidValues = [Low(TMyEnum)..High(TMyEnum)] - meNOTUSED; 


    if NOT (aValue in meValidValues) then 
    // etc 
+2

Tal vez usted puede aliviar el dolor de hacer esto mediante el uso de un tipo subrango: tipo TMyEnumWithDummy = ( meNOTUSED, meFirstValue, meSecondValue, meThirdValue ); TMyEnum = Succ (meNOTUSED) ..Alto (TMyEnumWithDummy); –

+1

Sí, de hecho, aunque si tiene "huecos" en la enumeración, entonces un subrango simple no será suficiente. En el caso en que encontré esto, tuve lagunas. Desafortunadamente, me simplifiqué demasiado para la "pregunta" inicial. Pero también actualizaré la respuesta con su sugerencia. – Deltics

28

enumeraciones no contiguas y enumeraciones que no comienzan en cero no tienen typeinfo. Para que se implemente typeinfo, debería estar en un formato diferente del existente tkEnumeration, debido a problemas de compatibilidad con versiones anteriores.

Consideré implementar una tkDiscontiguousEnumeration (o miembro posiblemente mejor nombrado) para Delphi 2010, pero el beneficio parecía pequeño teniendo en cuenta su escasez relativa y las dificultades en la enumeración: ¿cómo codifica los rangos de manera eficiente? Algunas codificaciones son mejores para algunos escenarios, peor para otros.

+6

Esa es información de fondo útil e interesante. Al menos podría haber considerado actualizar la documentación del error E2134. Esto proporciona un ejemplo de donde typeinfo no se produce, pero no da ninguna pista sobre estas consideraciones para los tipos enum. Por otra parte, me ha tomado casi 15 años de Delphi'ing sólido tropezar con esto, por lo que como usted dice que no es exactamente un problema común. :) – Deltics

Cuestiones relacionadas