如何将 class 引用 (metaclass) 作为参数传递给程序?

How to pass class reference (metaclass) as a parameter in procedure?

有两个对象:TFooTFoo2

还有一个class参考:TFooClass = class of TFoo;

两者都是TPersistent的后代。

他们有自己的构造函数:

type
  TFoo = class(TPersistent)
  private
    FC:Char;
  public
    constructor Create; virtual;
  published
    property C:Char read FC write FC;
  end;
    
  TFoo2 = class(TFoo)
  public
    constructor Create; override;
  end;

  TFooClass = class of TFoo;

...

constructor TFoo.Create;
begin
  inherited Create;
  C :=' 1';
end;
    
constructor TFoo2.Create;
begin
  inherited Create;
  C := '2';
end;

我想从一个字符串创建一个 TFoo2 对象,这实际上是它的 class 名称:'TFoo2'

这是程序,运行良好:

procedure Conjure(AClassName:string);
var
  PClass : TPersistentClass;
  p :TPersistent;
begin
  PClass := TPersistentClass(FindClass(AClassName))
  p := TFooClass(PClass).Create;  // <-- here is called appropriate constructor  
end;

现在,我想要类似的对象,例如:TBobodoTBobodo2

当然还有 class 参考:TBobodoClass = class of TBobodo;

等等...

现在,如何将 class 引用作为参数传递到过程中,以确保调用正确的构造函数?

procedure Conjure(AClassName:string; ACLSREF: ???? ); // <-- something like that 
var
  PClass : TPersistentClass;
  p :TPersistent;
begin
  PClass := TPersistentClass(FindClass(AClassName))
  p := ACLSREF(PClass).Create;  // <-- something like that  
end;

可能吗?

Delphi 7. 元类引用必须在编译时在调用站点显式显示,而不是在运行时处理。

在 Delphi 2009 年及以后,您 可能 1 可以使用 Generics 做一些事情,例如:

1: 我自己还没试过

type
  TConjureHelper = class
  public
    class procedure Conjure<TClassType>(const AClassName: string);
  end;

class procedure TConjureHelper.Conjure<TClassType>(const AClassName: string);
var
  PClass : TPersistentClass;
  p : TPersistent;
begin
  PClass := TPersistentClass(FindClass(AClassName));
  p := TClassType(PClass).Create;
  ...
end;

...

TConjureHelper.Conjure<TFooClass>('TFoo2');
TConjureHelper.Conjure<TBobodoClass>('TBobodo2');
...

但是Delphi7肯定不支持泛型

我遇到了同样的问题,经过一番努力,我找到了一个非常简单的解决方案:metaclass 正是为此目的而发明的! 在您的情况下,您可以将 metaclass 作为参数传递并直接使用它,而无需繁琐的查找 class 和类型转换。

type
  TFooClass = class of TFoo;

procedure Conjure(aFooClass : TFooClass); // <-- something like that 
var
  p :TPersistent;
begin
  p := aFooClass.Create;  // it will work!
end;

通过调用,您只需使用:

Conjure(TFoo); // <- for Foo class or
Conjure(TFoo2); // <- for Foo2 class and so on