2009-09-14 9 views
16

Ho dichiarato il seguente tipo di enum in cui voglio che il primo membro abbia il valore ordinale di 1 (uno) piuttosto che il solito 0 (zero) :Perché ottengo l'errore "type has no typeinfo" con un enum type

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

Se chiamo TypeInfo(), ad esempio, come parte di una chiamata a GetEnumName(), ottengo un errore di compilazione:

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

ERRORE: "E2134: Tipo 'TMyEnum' non ha typeinfo"

Perché è questo?

So che le classi hanno solo typeinfo se sono compilati con la $ M opzione compilatore attivata o (derivare da qualche classe che era, come ad esempio TPersistent), ma non pensavo che ci fossero delle condizioni particolari per avere typeinfo per i tipi di enum.

risposta

18

Le informazioni sul tipo non sono supportate per le enumerazioni in cui sono assegnati specifici valori ordinali che generano membri enum con valori ordinali diversi da quelli che verrebbero normalmente assegnati dal compilatore.

Se valori specifici sono essenziali o desiderabili, i membri di enum "non utilizzati" dovranno essere inseriti per "tamponare" l'enum come richiesto. ad esempio (indentazione addizionale per l'accento solo):

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

un sottoinsieme può quindi essere utilizzato per "filtrare" il valore iniziale inutilizzato:

TValidMyEnum = meFirstValue..meThirdValue; 

Anche se si potrebbe quindi prendere in considerazione rinominando l'enum originale digita in modo che il tipo di subrange possa essere utilizzato per tutto il progetto.

Un sottoinsieme non è sufficiente se l'enumerazione contiene "gap":

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

In questo caso non c'è semplicemente modo per estendere la portata fase di compilazione controllo per escludere i membri inutilizzati, ma un paio di set tipi semplificherà l'attività di attuare qualsiasi necessaria runtime controlli:

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

Forse si può alleviare il dolore di fare questo utilizzando un tipo subrange: tipo TMyEnumWithDummy = ( meNOTUSED, meFirstValue, meSecondValue, meThirdValue ); TMyEnum = Succ (meNOTUSED) ..Alta (TMyEnumWithDummy); –

+1

Sì, in effetti, anche se si dispone di "spazi vuoti" nell'enumerazione, un sottosistema semplice non sarà sufficiente. Nel caso in cui mi sono imbattuto in questo ho avuto lacune - Purtroppo ho semplificato troppo per la "domanda" iniziale. Ma aggiornerò la risposta anche con il tuo suggerimento. – Deltics

28

enumerazioni contiguo ed enumerazioni, che non iniziano a zero non hanno typeinfo. Affinché typeinfo possa essere implementato, dovrebbe essere in un formato diverso dall'esistente tkEnumeration, a causa di problemi di compatibilità con le versioni precedenti.

Ho considerato l'implementazione di un tkDiscontiguousEnumeration (o possibilmente un membro con un nome migliore) per Delphi 2010, ma il vantaggio sembrava piccolo considerando la loro relativa scarsità e le difficoltà di enumerazione - come si codificano gli intervalli in modo efficiente? Alcune codifiche sono migliori per alcuni scenari, peggio per gli altri.

+6

Ecco alcune informazioni di base utili e interessanti. Potresti aver almeno considerato di aggiornare la documentazione per l'errore E2134. Questo fornisce un esempio di dove typeinfo non viene prodotto ma non fornisce alcun indizio su queste considerazioni per i tipi di enumerazione. Poi di nuovo, ci sono voluti quasi 15 anni di solido Delphi per farmi inciampare su questo, quindi come dici tu non è esattamente un problema comune. :) – Deltics