考虑这样的枚举:
type
TTypeOfData = (
[XmlName('ABC')] todABC,
[XmlName('DEF')] todDEF,
[XmlName('GHI')] todGHI
);
其中 XmlName 是一个自定义属性,用于定义此枚举成员的序列化字符串。
如何探索附加到此枚举的每个成员的属性?
考虑这样的枚举:
type
TTypeOfData = (
[XmlName('ABC')] todABC,
[XmlName('DEF')] todDEF,
[XmlName('GHI')] todGHI
);
其中 XmlName 是一个自定义属性,用于定义此枚举成员的序列化字符串。
如何探索附加到此枚举的每个成员的属性?
虽然 Barry 清楚地回答了您关于枚举元素属性的问题,但我将尝试另一个建议。从您的示例中,您在 Delphi 中为每个枚举元素添加 'tod' 前缀,因为枚举元素在范围内是全局的(即,如果除了 todABC 枚举元素之外,您在范围内还有标识符 todABC,您可以获得一些奇怪的行为)。
从 D2007 开始,我们引入了“范围枚举”的概念,当启用该概念时,要求您使用枚举本身的标识符来限定枚举元素。例如:
{$SCOPEDENUMS ON}
type
TTypeOfData = (ABC,DEF,GHI);
将要求您将 ABC 元素称为 TTypeOfData.ABC。这允许您使用不带前缀的枚举元素标识符,并且不会冒发生冲突的风险,因为元素是“范围”到枚举的。启用 {$SCOPEDENUMS} 时声明的任何枚举都将以这种方式运行。
鉴于此,您现在可以安全地使用 RTTI 以您希望的格式获取实际的枚举元素名称。
与枚举中的元素关联的属性当前未存储在可执行文件的 Win32 RTTI 数据中。RTTI 已经对可执行文件大小的公平增加负有责任,因此必须在某处画出一些线。Delphi Win32 中的属性支持类型、记录字段以及字段、方法、它们的参数和类的属性。
由于与 Delphi for .NET 的向后兼容性,属性声明不会导致错误。
以下是网络上 Delphi 2010 中 RTTI 的一个很好的概述:http ://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html
您可以使用单元 TypInfo (GetEnumValue, GetEnumName) 中的“OLD”RTTI 函数获取枚举值并返回序数。并剪掉小写字母,您会得到与上面相同的结果,但它没有那么灵活。
好的,我想我找到了更好的解决方案。我声明了一个新的属性类型,例如:
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;
对于那些对该问题的实际解决方案感兴趣的人,我以这种方式解决了它:
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;
我在 const 部分使用字符串数组:
type
TTypeOfData = (
todABC,
todDEF,
todGHI
);
const
TypeOfDataText: array[TTypeOfData] of string = (
'ABC',
'DEF',
'GHI'
);