5

一連の列挙型を使用して内部の値を開始できる汎用クラスを作成しようとしています。例えば:

constructor TManager<TEnum>.Create;
var
  enum: TEnum;
  enumObj: TMyObject;
begin
  fMyObjectList:=  TObjectDictionary<TEnum,TMyObject>.Create([doOwnsValues],10);
  for enum:= Low(TEnum) to High(TEnum) do
  begin
    enumObj:= TMyObject.Create();
    fMyObjectList.Add(enum, enumObj);
  end;
end;

さらに、後のメソッドは、列挙値を介してオブジェクトをフェッチします。次に例を示します。

function TManager<TEnum>.Fetch(enum: TEnum): TMyObject;
begin
  fMyObjectList.TryGetValue(enum, Result);
end;

ただし、ジェネリック パラメータとして渡すと、デルファイは TEnum が列挙型になることを知りません。何らかの方法でそれを強制することはできますか?

4

2 に答える 2

7

David が述べたように、実行時に RTTI を使用するのが最善の方法です。

    type  
      TRttiHelp = record
        class procedure EnumIter<TEnum {:enum}>; static;
      end;

    class procedure TRttiHelp.EnumIter<TEnum {:enum}>;
    var
      typeInf: PTypeInfo;
      typeData: PTypeData;
      iterValue: Integer;
    begin
      typeInf := PTypeInfo(TypeInfo(TEnum));
      if typeInf^.Kind <> tkEnumeration then
        raise EInvalidCast.CreateRes(@SInvalidCast);

      typeData := GetTypeData(typeInf);
      for iterValue := typeData.MinValue to typeData.MaxValue do
        WhateverYouWish;
    end;  

列挙型に次のような値が定義されている場合、コードがどのように動作するかはわかりませんが

    (a=9, b=19, c=25)

編集:

列挙型に戻りたい場合は、Jim Ferguson による列挙型ヘルパー クラスiterValueから取得した次の関数を使用できます。

class function TRttiHelp.EnumValue<TEnum {:enum}>(const aValue: Integer): TEnum;
var
  typeInf: PTypeInfo;
begin
  typeInf := PTypeInfo(TypeInfo(TEnum));
  if typeInf^.Kind <> tkEnumeration then
    raise EInvalidCast.CreateRes(@SInvalidCast);

  case GetTypeData(typeInf)^.OrdType of
    otUByte, otSByte:
      PByte(@Result)^ := aValue;
    otUWord, otSWord:
      PWord(@Result)^ := aValue;
    otULong, otSLong:
      PInteger(@Result)^ := aValue;
  else
    raise EInvalidCast.CreateRes(@SInvalidCast);
  end;
end;

次に、一般的に提供された を、コンストラクターで辞書へのインデックスとして使用できます。

于 2012-09-12T07:09:52.437 に答える
2

ジェネリック クラスで使用できるようlow()にジェネリック パラメータを制約することはできません。high()使用できる制約は、クラスまたはインターフェイスの制約のみです。

私の知る限りでは、この言語は汎用列挙型を列挙する汎用的な方法を提供していません。おそらく最善の方法は、RTTI を使用して、コンパイル時の型の安全性を犠牲にすることです (Tobias が示しているように)。


Tobias's answer へのコメントを読んだ後、ここで本当に欲しいのは TObjectDictionary<TEnum,TMyObject>. これは、キーTMyObjectを指定してインスタンスを検索できるようにするためです。そして、前者がインスタンスの所有権を引き継ぐためではなく、TEnum必要です。完了したら、誰かがそれらをすべて解放する必要があります。TObjectDictionaryTDictionaryTMyObjectTObjectDictionary

この所有権側の例については、@RRUZ の回答を参照してください: Generics.Collections.TObjectDictionary の使用例

于 2012-09-12T06:20:50.257 に答える