考虑到这样一个枚举:德尔福2010 RTTI:探索枚举
type
TTypeOfData = (
[XmlName('ABC')] todABC,
[XmlName('DEF')] todDEF,
[XmlName('GHI')] todGHI
);
哪里XmlName是用来定义此枚举的成员序列化字符串自定义属性。
我该如何探索附属于此枚举每个成员的属性?
考虑到这样一个枚举:德尔福2010 RTTI:探索枚举
type
TTypeOfData = (
[XmlName('ABC')] todABC,
[XmlName('DEF')] todDEF,
[XmlName('GHI')] todGHI
);
哪里XmlName是用来定义此枚举的成员序列化字符串自定义属性。
我该如何探索附属于此枚举每个成员的属性?
与枚举中的元素相关联的属性当前未存储在可执行文件中的Win32 RTTI数据中。 RTTI已经负责公平地增加可执行文件的大小,因此必须在某处绘制一些行。 Delphi Win32中的属性支持类型,记录字段,字段,方法,它们的参数和类的属性。
属性声明不会因为与Delphi for .NET的向后兼容性而导致错误。
这是RTTI的德尔福2010年一个很好的概述网站:http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html
你可以得到枚举值和使用单位TypInfo(GetEnumValue,GetEnumName)“旧” RTTI功能恢复的序号。并剪下小写字母,得到与上面相同的结果,但不够灵活。
虽然巴里明确地回答了你关于枚举元素的属性的问题,但我会采取另一个暗示。在你的例子中,你使用'tod'作为每个枚举元素的前缀,因为在Delphi中是传统的,因为枚举元素是全局的(即,如果除了todABC枚举元素之外,你还有一个标识符todABC,奇怪的行为)。
从D2007开始,我们引入了“范围枚举”的概念,它在启用时要求您使用枚举本身的标识符限定枚举元素。例如:
{$SCOPEDENUMS ON}
type
TTypeOfData = (ABC,DEF,GHI);
将要求您将ABC元素称为TTypeOfData.ABC。这使您可以使用不带前缀的枚举元素标识符,并且不会因为元素被“范围限定”为枚举而发生冲突。在{$ SCOPEDENUMS}启用时声明的任何枚举都将以这种方式运行。
鉴于此,您现在可以安全地使用RTTI以您希望的格式获取实际的枚举元素名称。
谢谢艾伦, 这是一个坏榜样。我的枚举有点复杂,并且序列化的字符串与枚举成员不同。 – ZeDalaye 2010-01-26 07:35:09
唷,那很酷!不知道,总是不喜欢全球混乱与丑陋的前缀妥协,必须使用枚举... – 2010-01-26 13:38:25
@ZeDalaye, 我怀疑,但是,如果有一些有用的金块在我的建议...如果不,我相信有人会觉得它有用。 – 2010-01-26 17:20:58
对于那些谁在实际解决这一问题interrested,我解决了这样的说法:
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来寻找一类功能conventionnaly命名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;
好吧我想我找到了一个更好的解决方案。我声明了一个新的属性类型,例如:
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;
太棒了!这个问题最接近的答案.. – 2012-08-06 16:04:06
和字符串数组常量部分:
type
TTypeOfData = (
todABC,
todDEF,
todGHI
);
const
TypeOfDataText: array[TTypeOfData] of string = (
'ABC',
'DEF',
'GHI'
);
良好的讲解上。但在这种情况下,IMO应该引起“不支持的语言功能”警告,就像其他无效属性一样。 – 2010-01-25 20:11:26