如何访问 Metaclass 引用的 TList 中的 class 变量?
How to access class variables in a TList of Metaclass references?
我有一个 class 这样的:
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
个 class 是这样的:
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;
但是这个returns defDipsplay
而不是Caesar Cipher
。我认为这是我在列表中做错的地方,因为当我直接从 class 显示它时它显示正常:
ShowMessage(TCipher.ClassName + ' . ' + TCipher.sDisplayName);
ShowMessage(TCaesar.ClassName + ' . ' + TCaesar.sDisplayName);
您在 TCaesar
中重新声明了 sName
和 sDisplayName
,因此它们在祖先 TCipher
class 中隐藏了同名变量。只需删除该声明,您就会得到预期的行为。
TCaesar = class(TCipher)
private
public
function Encrypt(sText: String; Key: TObject): String; override;
function Decrypt(sText: String; Key: TObject): String; override;
end;
sName
和 sDisplayName
字段在这里仍将是 TCaesar
的成员,因为它们将从 TCipher
继承。如果您在后代 class 中声明具有相同名称的新变量,那么它们将在通过后代类型的引用直接引用时隐藏祖先变量。但是,当使用将对象视为祖先的变量时,您将改为读取和写入祖先的字段。
您的变量声明为 class var
,因此它们特定于声明它们的每个 class。您在 TCaesar
中声明了 class
个变量,它们与 TCipher
中的 class
个变量同名,但是当您尝试在运行时通过 TCipherClass
metaclass 引用,编译器不知道 metaclass 指的是哪个实际的 class,所以它在编译时所能做的就是生成代码来访问 TCipher
-特定变量,而不是 TCaesar
-特定变量。
在这种情况下,我会建议使用class virtual
方法而不是class var
s,那么每个class可以override
方法与return不同运行时的值。
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;
我有一个 class 这样的:
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
个 class 是这样的:
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;
但是这个returns defDipsplay
而不是Caesar Cipher
。我认为这是我在列表中做错的地方,因为当我直接从 class 显示它时它显示正常:
ShowMessage(TCipher.ClassName + ' . ' + TCipher.sDisplayName);
ShowMessage(TCaesar.ClassName + ' . ' + TCaesar.sDisplayName);
您在 TCaesar
中重新声明了 sName
和 sDisplayName
,因此它们在祖先 TCipher
class 中隐藏了同名变量。只需删除该声明,您就会得到预期的行为。
TCaesar = class(TCipher)
private
public
function Encrypt(sText: String; Key: TObject): String; override;
function Decrypt(sText: String; Key: TObject): String; override;
end;
sName
和 sDisplayName
字段在这里仍将是 TCaesar
的成员,因为它们将从 TCipher
继承。如果您在后代 class 中声明具有相同名称的新变量,那么它们将在通过后代类型的引用直接引用时隐藏祖先变量。但是,当使用将对象视为祖先的变量时,您将改为读取和写入祖先的字段。
您的变量声明为 class var
,因此它们特定于声明它们的每个 class。您在 TCaesar
中声明了 class
个变量,它们与 TCipher
中的 class
个变量同名,但是当您尝试在运行时通过 TCipherClass
metaclass 引用,编译器不知道 metaclass 指的是哪个实际的 class,所以它在编译时所能做的就是生成代码来访问 TCipher
-特定变量,而不是 TCaesar
-特定变量。
在这种情况下,我会建议使用class virtual
方法而不是class var
s,那么每个class可以override
方法与return不同运行时的值。
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;