Delphi中能否将枚举类型作为参数传递并在多个函数间高效重用此类型?

2026-04-10 16:352阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计984个文字,预计阅读时间需要4分钟。

Delphi中能否将枚举类型作为参数传递并在多个函数间高效重用此类型?

我想实现类似虚拟代码的功能:定义 CommandSetOne=(Command1, Command2, Command3);定义 CommandSetTwo=(Command4, Command5, Command6);定义 TRobot=class procedure RegisterCommands(anyEnumerationType: TRttiEnumerationType);定义 Exe;

Delphi中能否将枚举类型作为参数传递并在多个函数间高效重用此类型?

我想要实现的就像虚拟代码:

type CommandSetOne = (Command1, Command2, Command3); CommandSetTwo = (Command4, Command5, Command6); TRobot = class procedure RegisterCommands(anyEnumerationType : TRttiEnumerationType); procedure ExecuteCommands(anEnumeration : theEnumerationType); end;

我可能有多组命令,命令集中的任何命令都是可替换的.

TRobot有一个过程可以将枚举类型作为参数,他将保存此类型,将此类型用于ExecuteCommands过程.

关于传递任何枚举类型作为参数,我发现一种方法是使用TRttiEnumerationType,在调用方面它应该如下所示:

var rttiContext : TRttiContext; typeref : TRttiType; RobotA : TRobot; begin rttiContext := TRttiContext.Create(); RobotA := TRobot.Create(); RobotA.RegisterCommands(rttiContext.GetType(TypeInfo(CommandSetOne))); end;

但我坚持传递Command1之类的命令.我已经为theEnumerationType尝试了Variant,但似乎我无法将Command1传递给它.

我知道如果我使用类似TStringList的东西,这是一个更容易的方法来做我想要的,但我想在符合时间的情况下通过delphi进行检查,以防我输入错误的命令(使用TstringList我可以添加代码来检查运行)

所以真正的问题是:

>我应该为theEnumerationType使用哪种类型?
>如果不可能,使用Enumeration的任何其他解决方案?
>或任何解决方案可以提供符合时间检查以及灵活的结构?

编辑:

感谢David建议,我应该使用两个Rtti的东西,所以为了说清楚,我添加了RegisterCommands的实现

implementation procedure TRobot.RegisterCommands(anyEnumerationType : TRttiEnumerationType); begin theEnumerationType := anyEnumerationType; end; procedure TRobot.ExecuteCommands (anyEnumerationValueoftheType : ???); begin //do something with the command end;

什么适合该类型的任何枚举值?

例如,如果我在RegisterCommands中使用CommandSetOne,
delphi如何接受Command1或Command2或Command3?

更具体地说,delphi只能为Command1或Command2或Command3限制空间吗?意味着如果我把Command4它给我一个编译错误?

每当你发现自己想要将某种类型的东西作为参数传递时,goto解决方案就是泛型.

我们将滥用枚举实际上是一个整数不足的事实.
假设您在枚举标签的字符串表示中编码了实际命令.
例如

TCommands = (Left, Right, Up, Down); TRobot = class private FRegisteredCommands: TDictionary<integer, string>; public procedure RegisterCommand<E: record>(Enum : E); procedure ExecuteCommand<E: record>(Enum : E); end; procedure TRobot.RegisterCommand<E: record>(Enum: E); var Key: integer absolute Enum; //typesafe, because of the if below. Info: PTypeInfo; begin if GetTypeKind(E) <> tkEnumeration then raise Exception.Create('Enum is not an enum'); //Added type safety: if not(TypeInfo(E) = TypeInfo(TRobotCommand1)) or not(TypeInfo(E) = TypeInfo(TRobotCommend2)) then raise .... Info:= TypeInfo(Enum); FRegisteredCommands.Add(Key, GetEnumName(Info, Key)); end;

The compiler will remove all this if code if these checks are true and only generate the code if these checks are false, because GetTypeKind is a compiler intrinsic routine这意味着执行这些检查需要零运行时间
请注意,如果疯狂快速性能是你的事情,你可以使用if TypeInfo(E)= TypeInfo(TMyCommandSet)编译器内在技巧来硬编码命令.

请注意,在早期的Delphi中,绝对指令会导致编译器内部错误(在西雅图,它可以100%正常工作).在这种情况下,更改代码如下:

procedure TRobot.RegisterCommand<E: record>(Enum: E); var Key: integer; Info: PTypeInfo; begin .... Key:= PInteger(@Enum)^; .....

如果给定的TRobot后代只接受单一类型的命令,那么我将泛型类型移动到TRobot,如下所示:

TBaseRobot<E: record> = class(TObject) constructor Create; virtual; procedure RegisterCommand(Enum: E); //only implement once, see above. procedure ExecuteCommand(Enum: E); virtual; abstract; //implement in descendents. .... constructor TBaseRobot<E>.Create; begin inherited Create; if GetTypeKind(E) <> tkEnumeration then raise('error: details'); end; TRobotA = class(TBaseRobot<TMyEnum>) procedure ExecuteCommand(Enum: TMyEnum); override; end; ....

编辑
您可以在类构造函数中执行此操作,而不是在构造函数中执行检查.这样做的好处是,一旦您的应用程序启动,任何错误都会触发,而不是在您的测试中可能永远不会发生的某个随机时间.

删除构造函数并将其替换为类构造函数,如下所示:

//You should never name a class constructor `create`. class constructor don't create anything, they init stuff. class constructor TBaseRobot<E>.Init; begin if GetTypeKind(E) <> tkEnumeration then raise('error: details'); end;

本文共计984个文字,预计阅读时间需要4分钟。

Delphi中能否将枚举类型作为参数传递并在多个函数间高效重用此类型?

我想实现类似虚拟代码的功能:定义 CommandSetOne=(Command1, Command2, Command3);定义 CommandSetTwo=(Command4, Command5, Command6);定义 TRobot=class procedure RegisterCommands(anyEnumerationType: TRttiEnumerationType);定义 Exe;

Delphi中能否将枚举类型作为参数传递并在多个函数间高效重用此类型?

我想要实现的就像虚拟代码:

type CommandSetOne = (Command1, Command2, Command3); CommandSetTwo = (Command4, Command5, Command6); TRobot = class procedure RegisterCommands(anyEnumerationType : TRttiEnumerationType); procedure ExecuteCommands(anEnumeration : theEnumerationType); end;

我可能有多组命令,命令集中的任何命令都是可替换的.

TRobot有一个过程可以将枚举类型作为参数,他将保存此类型,将此类型用于ExecuteCommands过程.

关于传递任何枚举类型作为参数,我发现一种方法是使用TRttiEnumerationType,在调用方面它应该如下所示:

var rttiContext : TRttiContext; typeref : TRttiType; RobotA : TRobot; begin rttiContext := TRttiContext.Create(); RobotA := TRobot.Create(); RobotA.RegisterCommands(rttiContext.GetType(TypeInfo(CommandSetOne))); end;

但我坚持传递Command1之类的命令.我已经为theEnumerationType尝试了Variant,但似乎我无法将Command1传递给它.

我知道如果我使用类似TStringList的东西,这是一个更容易的方法来做我想要的,但我想在符合时间的情况下通过delphi进行检查,以防我输入错误的命令(使用TstringList我可以添加代码来检查运行)

所以真正的问题是:

>我应该为theEnumerationType使用哪种类型?
>如果不可能,使用Enumeration的任何其他解决方案?
>或任何解决方案可以提供符合时间检查以及灵活的结构?

编辑:

感谢David建议,我应该使用两个Rtti的东西,所以为了说清楚,我添加了RegisterCommands的实现

implementation procedure TRobot.RegisterCommands(anyEnumerationType : TRttiEnumerationType); begin theEnumerationType := anyEnumerationType; end; procedure TRobot.ExecuteCommands (anyEnumerationValueoftheType : ???); begin //do something with the command end;

什么适合该类型的任何枚举值?

例如,如果我在RegisterCommands中使用CommandSetOne,
delphi如何接受Command1或Command2或Command3?

更具体地说,delphi只能为Command1或Command2或Command3限制空间吗?意味着如果我把Command4它给我一个编译错误?

每当你发现自己想要将某种类型的东西作为参数传递时,goto解决方案就是泛型.

我们将滥用枚举实际上是一个整数不足的事实.
假设您在枚举标签的字符串表示中编码了实际命令.
例如

TCommands = (Left, Right, Up, Down); TRobot = class private FRegisteredCommands: TDictionary<integer, string>; public procedure RegisterCommand<E: record>(Enum : E); procedure ExecuteCommand<E: record>(Enum : E); end; procedure TRobot.RegisterCommand<E: record>(Enum: E); var Key: integer absolute Enum; //typesafe, because of the if below. Info: PTypeInfo; begin if GetTypeKind(E) <> tkEnumeration then raise Exception.Create('Enum is not an enum'); //Added type safety: if not(TypeInfo(E) = TypeInfo(TRobotCommand1)) or not(TypeInfo(E) = TypeInfo(TRobotCommend2)) then raise .... Info:= TypeInfo(Enum); FRegisteredCommands.Add(Key, GetEnumName(Info, Key)); end;

The compiler will remove all this if code if these checks are true and only generate the code if these checks are false, because GetTypeKind is a compiler intrinsic routine这意味着执行这些检查需要零运行时间
请注意,如果疯狂快速性能是你的事情,你可以使用if TypeInfo(E)= TypeInfo(TMyCommandSet)编译器内在技巧来硬编码命令.

请注意,在早期的Delphi中,绝对指令会导致编译器内部错误(在西雅图,它可以100%正常工作).在这种情况下,更改代码如下:

procedure TRobot.RegisterCommand<E: record>(Enum: E); var Key: integer; Info: PTypeInfo; begin .... Key:= PInteger(@Enum)^; .....

如果给定的TRobot后代只接受单一类型的命令,那么我将泛型类型移动到TRobot,如下所示:

TBaseRobot<E: record> = class(TObject) constructor Create; virtual; procedure RegisterCommand(Enum: E); //only implement once, see above. procedure ExecuteCommand(Enum: E); virtual; abstract; //implement in descendents. .... constructor TBaseRobot<E>.Create; begin inherited Create; if GetTypeKind(E) <> tkEnumeration then raise('error: details'); end; TRobotA = class(TBaseRobot<TMyEnum>) procedure ExecuteCommand(Enum: TMyEnum); override; end; ....

编辑
您可以在类构造函数中执行此操作,而不是在构造函数中执行检查.这样做的好处是,一旦您的应用程序启动,任何错误都会触发,而不是在您的测试中可能永远不会发生的某个随机时间.

删除构造函数并将其替换为类构造函数,如下所示:

//You should never name a class constructor `create`. class constructor don't create anything, they init stuff. class constructor TBaseRobot<E>.Init; begin if GetTypeKind(E) <> tkEnumeration then raise('error: details'); end;