delphi - 如何访问元类引用的 TList 中的类变量?
问题描述
我有这样的课:
type
TCipher = class
private
public
function Encrypt(sText: String; Key: TObject): String; virtual; abstract;
function Decrypt(sText: String; Key: TObject): String; virtual; abstract;
class var
sName: String;
sDisplayName: String;
end;
TCipherClass = class of TCipher;
TCaesar = class(TCipher)
private
public
function Encrypt(sText: String; Key: TObject): String; override;
function Decrypt(sText: String; Key: TObject): String; override;
class var
sName: String;
sDisplayName: String;
end;
implementation
function TCaesar.Encrypt(sText: String; Key: TObject): String;
begin
end;
function TCaesar.Decrypt(sText: String; Key: TObject): String;
begin
end;
initialization
TCipher.sName := 'defaultName';
TCipher.sDisplayName := 'defaultDipsplay';
ShowMessage(TCipher.sName + ' ' + TCipher.sDisplayName);
TCaesar.sName := 'caesar';
TCaesar.sDisplayName := 'Caesar Cipher';
ShowMessage(TCaesar.sName + ' ' + TCaesar.sDisplayName);
end.
在其他地方,我有这样TList
的课程:
var
lstCiphers: TList<TCipherClass>;
cipher: TCipherClass;
begin
lstCiphers := TList<TCipherClass>.Create;
lstCiphers.AddRange([TCaesar]);
for cipher in lstCiphers do
ShowMessage('In list: ' + cipher.ClassName + ' . ' + cipher.sDisplayName);
end;
但这会返回defDipsplay
而不是Caesar Cipher
. 我认为这是我在列表中做错的事情,因为当我直接从课堂上展示它时,它显示得很好:
ShowMessage(TCipher.ClassName + ' . ' + TCipher.sDisplayName);
ShowMessage(TCaesar.ClassName + ' . ' + TCaesar.sDisplayName);
解决方案
您的变量被声明为class var
,因此它们特定于声明它们的每个类。您class
声明的变量与 中的变量TCaesar
具有相同的名称,但是当您尝试在运行时通过元类引用访问这些变量时,编译器不知道元类引用的是哪个实际类,因此它只能在编译时做-time 是生成代码来访问-specific 变量,而不是-specific 变量。class
TCipher
TCipherClass
TCipher
TCaesar
在这种情况下,我建议使用class virtual
方法而不是class var
s,然后每个类可以override
在运行时返回不同的值的方法。
type
TCipher = class
public
function Encrypt(sText: String; Key: TObject): String; virtual; abstract;
function Decrypt(sText: String; Key: TObject): String; virtual; abstract;
class function CipherName: String; virtual;
class function DisplayName: String; virtual;
end;
TCipherClass = class of TCipher;
TCaesar = class(TCipher)
public
function Encrypt(sText: String; Key: TObject): String; override;
function Decrypt(sText: String; Key: TObject): String; override;
class function CipherName: String; override;
class function DisplayName: String; override;
end;
implementation
function TCaesar.Encrypt(sText: String; Key: TObject): String;
begin
...
end;
function TCaesar.Decrypt(sText: String; Key: TObject): String;
begin
...
end;
class function TCipher.CipherName: String;
begin
Result := 'defaultName';
end;
class function TCipher.DisplayName: String;
begin
Result := 'defaultDipsplay';
end;
class function TCaesar.CipherName: String;
begin
Result := 'caesar';
end;
class function TCaesar.DisplayName: String;
begin
Result := 'Caesar Cipher';
end;
initialization
ShowMessage(TCipher.CipherName + ' ' + TCipher.DisplayName);
ShowMessage(TCaesar.CipherName + ' ' + TCaesar.DisplayName);
end.
var
lstCiphers: TList<TCipherClass>;
cipher: TCipherClass;
begin
lstCiphers := TList<TCipherClass>.Create;
lstCiphers.Add(TCaesar);
for cipher in lstCiphers do
ShowMessage('In list: ' + cipher.ClassName + ' . ' + cipher.CipherName + '.' + cipher.DisplayName);
end;
推荐阅读
- flutter - 包裹在一行内被切割
- c# - 与三角形背面碰撞时如何忽略相机碰撞?
- python-3.x - 在 qml 中禁用最小化功能
- mysql - 如何在mysql中将日文日期格式转换并更新为真实的日期时间格式
- c# - 带有身份的 Blazor WebAssembly 的 SignalR Hub 授权
- d3.js - dc.ChoroplethChart 的问题
- rust - 在 rust 中重新编码 C++ 任务队列。期货是正确的抽象吗?
- linux - 使用热键后如何在 vim 中转到行尾?
- android - 启用 FLAG_LAYOUT_NO_LIMITS 时,选项子菜单会离开屏幕
- javascript - 如何在 JavaScript 中应用 display: flex 和 flex-direction: row?