そのような列挙を考慮する:
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 は enum 要素の属性に関するあなたの質問に明確に答えましたが、私は別の提案に挑戦します。あなたの例から、列挙型要素はスコープ内でグローバルであるため、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 との下位互換性があるため、属性の宣言によってエラーが発生することはありません。
わかりました、私はより良い解決策を見つけたと思います。新しい属性タイプを宣言します。例:
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;
これらは Web 上の Delphi 2010 の RTTI の概要です。
ユニット TypInfo (GetEnumValue、GetEnumName) の「OLD」RTTI 関数を使用して、列挙値を取得し、序数を戻すことができます。小文字を切り取ると、上記と同じ結果が得られますが、それほど柔軟ではありません。
その問題の実用的な解決策に興味がある人のために、私はそのように解決しました:
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'
);