13

そのような列挙を考慮する:

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

XmlName は、この列挙型のメンバーのシリアル化文字列を定義するために使用されるカスタム属性です。

この列挙型の各メンバーに関連付けられている属性を調べるにはどうすればよいですか?

4

6 に答える 6

19

Barry は enum 要素の属性に関するあなたの質問に明確に答えましたが、私は別の提案に挑戦します。あなたの例から、列挙型要素はスコープ内でグローバルであるため、Delphi で伝統的であるように、各列挙型要素に「tod」というプレフィックスを付けています (つまり、todABC 列挙型要素に加えてスコープ内に識別子 todABC がある場合、いくつかを取得できます)。奇妙な行動)。

D2007 以降、「スコープ付き列挙型」の概念を導入しました。これを有効にすると、列挙型要素を列挙型自体の識別子で修飾する必要があります。例えば:

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

ABC 要素を TTypeOfData.ABC として参照する必要があります。これにより、プレフィックスのない列挙要素識別子を使用でき、要素が列挙に「スコープ」されるため、競合が発生するリスクを回避できます。{$SCOPEDENUMS} が有効になっている間に宣言されたすべての列挙型は、このように動作します。

これで、RTTI を安全に使用して実際の列挙要素名を希望の形式で取得できるようになりました。

于 2010-01-25T21:33:44.880 に答える
14

列挙型の要素に関連付けられた属性は、現在、実行可能ファイルの Win32 RTTI データに格納されていません。RTTI はすでに実行可能ファイルのサイズを大幅に増加させているため、どこかに線を引く必要がありました。Delphi Win32 の属性は、タイプ、レコードのフィールド、クラスのフィールド、メソッド、それらのパラメータ、およびプロパティでサポートされています。

Delphi for .NET との下位互換性があるため、属性の宣言によってエラーが発生することはありません。

于 2010-01-25T18:47:27.303 に答える
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;
于 2010-04-12T09:09:29.707 に答える
3

これらは Web 上の Delphi 2010 の RTTI の概要です

ユニット TypInfo (GetEnumValue、GetEnumName) の「OLD」RTTI 関数を使用して、列挙値を取得し、序数を戻すことができます。小文字を切り取ると、上記と同じ結果が得られますが、それほど柔軟ではありません。

于 2010-01-25T19:12:40.630 に答える
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;
于 2010-01-26T07:47:37.550 に答える
0

constセクションで文字列の配列を使用します:

type
  TTypeOfData = (
    todABC,
    todDEF,  
    todGHI
  );

const
  TypeOfDataText: array[TTypeOfData] of string = (
    'ABC',
    'DEF',
    'GHI'
  );
于 2012-12-18T16:58:02.817 に答える