Delphi 2010 RTTI : Explore Enumerations

后端 未结 6 1917
挽巷
挽巷 2021-02-05 16:04

Considering such an enumeration :

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


        
相关标签:
6条回答
  • 2021-02-05 16:14

    For those who are interrested in a practical solution to that problem, I solved it that way :

    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;
    

    And later, in the serialization code, I use RTTI to look for a class function conventionnaly named AsString and call it with the property 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;
    
    0 讨论(0)
  • 2021-02-05 16:23

    Attributes associated with elements in enumerations are not currently stored in Win32 RTTI data in the executable. RTTI is already responsible for a fair increase in the size of executables, so some lines had to be drawn somewhere. Attributes in Delphi Win32 are supported on types, on fields of records, and fields, methods, their parameters, and properties of classes.

    The attribute declarations don't cause errors because of backward compatibility with Delphi for .NET.

    0 讨论(0)
  • 2021-02-05 16:32

    I use and array of string in the const section:

    type
      TTypeOfData = (
        todABC,
        todDEF,  
        todGHI
      );
    
    const
      TypeOfDataText: array[TTypeOfData] of string = (
        'ABC',
        'DEF',
        'GHI'
      );
    
    0 讨论(0)
  • 2021-02-05 16:33

    While Barry clearly answered your question regarding the attributes on enum elements, I'll take a stab at another suggestion. From your example, you're prefixing each enum element with 'tod' as is traditional in Delphi because enum elements are global in scope (ie. if you had an identifier todABC in scope in addition to the todABC enum elements, you could get some odd behaviors).

    Starting in D2007, we introduced the notion of "scoped enums" which, when enabled, require you to qualify the enum element with the identifier of the enum itself. For instance:

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

    Will require you to refer to the ABC element as TTypeOfData.ABC. This allows you to use non-prefixed enum element identifiers and not run the risk of having conflicts since the elements are "scoped" to the enumeration. Any enum declared while {$SCOPEDENUMS} is enabled will behave in this manner.

    Given that, you can now safely use the RTTI to get the actual enum element names in the format you wish.

    0 讨论(0)
  • 2021-02-05 16:36

    These is a good overview of RTTI in Delphi 2010 on the web: http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html

    You can get the enumeration values and back the ordinals using the "OLD" RTTI functions in the unit TypInfo (GetEnumValue, GetEnumName). And clip off the lowercase letters you get the same result as above but it is not as flexible.

    0 讨论(0)
  • 2021-02-05 16:36

    Ok I think I have found a better solution. I declare a new attribute type, e.g.:

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

    Now I add attributes to my enumeration:

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

    Now it is easy to access the attributes by its ordinal:

    RttiType := RttiContext.FindType ('ExampleUnit.TExampleEnum');
    RttiAttributes := Rttitype.GetAttributes;
    Test := TEnumAttributes(RttiAttributes[index]).Caption;
    
    0 讨论(0)
提交回复
热议问题