使用带有泛型的枚举

时间:2012-09-11 22:53:45

标签: delphi generics enums

我正在尝试创建一个泛型类,我可以使用一组枚举来启动里面的值。例如:

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;

但是,作为通用参数传递,delphi不知道TEnum将是一个枚举。我能以某种方式强制执行吗?

2 个答案:

答案 0 :(得分:5)

正如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)

编辑:

如果您想将iterValue返回枚举,可以使用以下函数,取自enum helper class by Jim Ferguson

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;

然后,您可以使用通常提供的作为构造函数中字典的索引。

答案 1 :(得分:2)

您不能约束泛型参数,以便可以在泛型类中使用low()high()。唯一可用的约束是类或接口约束。

据我所知,该语言没有提供枚举通用枚举类型的通用方法。您可以做的最好的事情就是使用RTTI,牺牲编译时类型的安全性(如Tobias所示)。


阅读了对Tobias的回答后,你真正想要的是TObjectDictionary<TEnum,TMyObject>。那是因为您希望能够在TMyObject密钥的情况下找到TEnum个实例。并且您希望TObjectDictionary而不是TDictionary,因为前者接管了TMyObject个实例的所有权。完成后你需要有人释放它们,你也可以让TObjectDictionary为你做。

有关此所有权方面的示例,请参阅@ RRUZ的答案:Example for using Generics.Collections.TObjectDictionary