2010-01-25 12 views
12

Rozpatrując takie wyliczenie:Delphi 2010 RTTI Przeglądaj Wyliczenia

type 
    TTypeOfData = (
    [XmlName('ABC')] todABC, 
    [XmlName('DEF')] todDEF, 
    [XmlName('GHI')] todGHI 
); 

Gdzie XmlName jest niestandardowy atrybut używany do określenia ciąg serializacji dla członków tego wyliczenia.

Jak mogę zbadać atrybuty dołączone do każdego członka tego wyliczenia?

Odpowiedz

14

Atrybuty powiązane z elementami w wyliczeniach nie są obecnie przechowywane w danych RTT Win32 w pliku wykonywalnym. RTTI jest już odpowiedzialne za sprawiedliwy wzrost wielkości plików wykonywalnych, więc trzeba było gdzieś narysować kilka linii. Atrybuty w Delphi Win32 są obsługiwane na typach, polach rekordów oraz polach, metodach, ich parametrach i właściwościach klas.

Deklaracje atrybutów nie powodują błędów z powodu kompatybilności wstecznej z Delphi dla .NET.

+8

Dobre wyjaśnienie na. Ale w tym przypadku IMO powinny one powodować ostrzeżenie "nieobsługiwanym językiem", tak jak robi to inne nieprawidłowe użycie atrybutów. –

17

Podczas gdy Barry wyraźnie odpowiedział na twoje pytanie dotyczące atrybutów na elementach enum, wezmę ukłucie na inną sugestię. Z twojego przykładu, prefiksujesz każdy element enum z "tod", tak jak jest tradycyjnie w Delphi, ponieważ elementy enum mają zasięg globalny (tj. Jeśli masz identyfikator TodABC w zakresie oprócz elementów enum todABC, możesz uzyskać trochę dziwne zachowania).

Począwszy od D2007, wprowadziliśmy pojęcie "enopingu", które po włączeniu wymaga zakwalifikowania elementu wyliczeniowego z identyfikatorem samego enum. Na przykład:

{$SCOPEDENUMS ON} 
type 
    TTypeOfData = (ABC,DEF,GHI); 

Wymaga od użytkownika odwołania do elementu ABC jako TTypeOfData.ABC. Pozwala to na użycie niezamkniętych identyfikatorów elementów wyliczających i nie powoduje ryzyka wystąpienia konfliktów, ponieważ elementy są "ograniczone" do wyliczenia. Każde enum zadeklarowane, gdy włączone jest {$ SCOPEDENUMS}, będzie się zachowywać w ten sposób.

Biorąc pod uwagę, że można teraz bezpiecznie używać RTTI, aby uzyskać rzeczywiste nazwy elementów enum w pożądanym formacie.

+0

Dziękuję Allen, To był zły przykład. Moje wyliczenie jest nieco bardziej złożone, a łańcuchy serializowane nie są tym samym, co elementy wyliczeniowe. – ZeDalaye

+0

Uff, fajnie! Nie wiedziałem, że zawsze nie podobał mi się globalny bałagan a brzydkie prefiksy kompromisowe trzeba było zrobić z enum ... –

+0

@ZeDalaye, Podejrzewałem, że jednak jeśli jest jakaś bryłka użyteczności w mojej sugestii ... Jeśli nie, jestem pewien, że ktoś może uznać to za przydatne. –

1

Dla tych, którzy są interrested w praktycznym rozwiązaniem tego problemu, I rozwiązać to w ten sposób:

type 
    TTypeOfData = (todABC, todDEF, todGHI); 

    TMySerializableClass = class 
    private 
    FType: TTypeOfData; 
    public 
    property &Type: TTypeOfData read FType write FType; 
    class function TypeOfDataAsString(&Type: TTypeOfData): String; 
    end; 

implementation 

class function TMySerializableClass.TypeOfDataAsString(&Type: TTypeOfData): String; 
const 
    TYPE_STRING: array[TypeOfDataAsString] of String = ('ABC', 'DEF', 'GHI); 
begin 
    Result := TYPE_STRING[&Type]; 
end; 

A później, w kodzie serializacji, używam RTTI szukać funkcji klasy conventionnaly nazwie AsString i zadzwoń do niego z własnością TValue:

procedure Serialize(const V: TValue); 
var 
    N: String; 
    T: TRttiType; 
    F: TRttiField; 
    M: TRttiMethod; 
    R: TValue; 
begin 
    case V.TypeInfo^.Kind of 
    tkEnumeration: 
    begin 
    T := Ctx.GetType(TypeInfo(TMySerializableClass)); 
    N := V.TypeInfo.Name + 'AsString'; 
    if N[1] = 'T' then 
     Delete(N, 1, 1); 
    M := T.GetMethod(N); 
    if (M <> nil) and M.IsClassMethod and (M.MethodKind = mkClassFunction) and (M.ReturnType.TypeKind = tkUString) then 
    begin 
     R := M.Invoke(TTicket, [V]); 
     // serialize R.AsString 
    end; 
    end; 
    ... 
end; 
+1

To rozsądne rozwiązanie. Bardzo podoba mi się też sugestia Allena Bauera. –

+0

Co oznacza właściwość '&' in 'property & Type'? – Shannon

+0

Typ jest słowem zarezerwowanym w Delphi. Prefixowanie za pomocą i umożliwia użycie tego słowa jako identyfikatora. – ZeDalaye

3

Ok Myślę, że znalazłem lepsze rozwiązanie. Deklaruję nowy typ atrybutu, np.:

TEnumAttribute = class (TCustomAttribute) 
    private 
    FCaption : string; 
    public 
    constructor Create (const Caption : string); 
    property Caption : string read FCaption write FCaption; 
end; 

Teraz dodaję atrybuty moim wyliczenie:

[TEnumAttribute ('Normal')] 
[TEnumAttribute ('High')] 
TExampleEnum = (eeNormal,eeHigh); 

Teraz jest łatwy dostęp do atrybutów przez jego porządkowa:

RttiType := RttiContext.FindType ('ExampleUnit.TExampleEnum'); 
RttiAttributes := Rttitype.GetAttributes; 
Test := TEnumAttributes(RttiAttributes[index]).Caption; 
+0

świetnie! najbardziej bliska odpowiedź na to pytanie .. –

0

używam i tablicę ciągów z sekcja const:

type 
    TTypeOfData = (
    todABC, 
    todDEF, 
    todGHI 
); 

const 
    TypeOfDataText: array[TTypeOfData] of string = (
    'ABC', 
    'DEF', 
    'GHI' 
); 
Powiązane problemy