Delphi 2010 RTTI:探索枚举

时间:2010-01-25 17:19:49

标签: delphi delphi-2010 enumeration rtti

考虑这样的枚举:

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

其中XmlName是一个自定义属性,用于为此枚举的成员定义序列化字符串。

如何浏览附加到此枚举的每个成员的属性?

6 个答案:

答案 0 :(得分:18)

虽然Barry清楚地回答了关于枚举元素属性的问题,但我还是会采取另一种建议。从你的例子中,你在每个枚举元素前面加上'tod',这在Delphi中是传统的,因为枚举元素在范围上是全局的(即如果除了todABC枚举元素之外你在范围内有标识符todABC,你可以得到一些奇怪的行为)。

从D2007开始,我们引入了“scoped enums”的概念,当启用它时,要求您使用枚举本身的标识符限定enum元素。例如:

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

将要求您将ABC元素称为TTypeOfData.ABC。这允许您使用非前缀的枚举元素标识符,并且不会冒着冲突的风险,因为元素被“限定”为枚举。启用{$ SCOPEDENUMS}时声明的任何枚举都将以这种方式运行。

鉴于此,您现在可以安全地使用RTTI以您希望的格式获取实际的枚举元素名称。

答案 1 :(得分:14)

与枚举中的元素相关联的属性当前未存储在可执行文件中的Win32 RTTI数据中。 RTTI已经负责公平地增加可执行文件的大小,因此必须在某处绘制一些行。 Delphi Win32中的属性在类型,记录字段,字段,方法,参数和类属性上受支持。

由于与Delphi for .NET的向后兼容性,属性声明不会导致错误。

答案 2 :(得分:3)

这些是对网络上Delphi 2010中RTTI的一个很好的概述:http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html

您可以使用单位TypInfo(GetEnumValue,GetEnumName)中的“OLD”RTTI函数获取枚举值并返回序数。并剪掉小写字母,你会得到与上面相同的结果,但它不够灵活。

答案 3 :(得分:3)

好的我觉得我找到了更好的解决方案。我声明了一个新的属性类型,例如:

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

现在我将属性添加到枚举中:

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

现在可以通过序数轻松访问属性:

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

答案 4 :(得分:1)

对那些对这个问题有实际解决方案感兴趣的人,我就这样解决了:

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;

后来,在序列化代码中,我使用RTTI查找一个名为AsString的类函数,并使用属性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;

答案 5 :(得分:0)

我在const部分中使用了字符串数组:

type
  TTypeOfData = (
    todABC,
    todDEF,  
    todGHI
  );

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