使用泛型的枚举
我正在尝试创建一个通用类,我可以使用一组枚举来启动其中的值。例如:
I'm trying to create a generic class to which I can use a set of enums to initiate the values inside. For example:
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;
此外,以后的方法将通过枚举值获取对象,例如:
Additionally, later methods will fetch objects, via the enum value, for example:
function TManager<TEnum>.Fetch(enum: TEnum): TMyObject;
begin
fMyObjectList.TryGetValue(enum, Result);
end;
但是,作为通用参数传递,delphi不知道TEnum将是一个枚举。我可以以某种方式执行吗?
However, passing as a generic parameter, delphi doesn't know that TEnum is going to be an enum. Can I enforce that in some way?
正如David所提到的那样,您可以做的最好的是在运行时使用RTTI。
As David mentioned the best you can do is at runtime with 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;
虽然我不知道代码行为如何,当你的枚举已经定义了值,例如
Although I don't know how the code behaves when your enum has defined values such as
(a=9, b=19, c=25)
编辑:
如果你想返回 iterValue
到枚举,您可以使用以下功能,从 enf helper class by Jim Ferguson
If you would like to return iterValue
to the enum, you may use the following function, taken from a 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;
然后,您可以使用一般提供的构造函数中的字典索引。
You may then use the generically provided as the index to the dictionary in your constructor.