首先,需要解释一下我的情况:
我有一个样例接口,由不同的类实现,这些类可能并不总是有共同的祖先:
IMyInterface = interface
['{1BD8F7E3-2C8B-4138-841B-28686708DA4D}']
procedure DoSomething;
end;
TMyImpl = class(TInterfacedPersistent, IMyInterface)
procedure DoSomething;
end;
TMyImp2 = class(TInterfacedObject, IMyInterface)
procedure DoSomething;
end;
我还有一个工厂方法,用于创建实现我的接口的对象实例。我的工厂方法接收类名作为其参数:
function GetImplementation(const AClassName: string): IMyInterface;
我尝试了两种方法来实现这个工厂方法,第一种方法是使用扩展RTTI:
var
ctx : TRttiContext;
t : TRttiInstanceType;
begin
t := ctx.FindType(AClassName).AsInstance;
if Assigned(t) then
Result := t.GetMethod('Create').Invoke(t.MetaclassType, []).AsInterface as IMyInterface;
end;
在这种方法中,我调用了默认构造函数,在我的场景中这是可以的。问题在于,在运行时,我会收到一个错误,告诉我对象不支持IMyInterface。更重要的是,创建的对象没有分配给接口变量;因此,它将被泄漏。我还尝试使用TValue.AsType方法返回值,但它给我带来了访问冲突:
function GetImplementation(const AClassName: string): IMyInterface;
var
ctx : TRttiContext;
rt : TRttiInstanceType;
V : TValue;
begin
rt := ctx.FindType(AClassName).AsInstance;
if Assigned(rt) then
begin
V := rt.GetMethod('Create').Invoke(rt.MetaclassType, []);
Result := V.AsType<IMyInterface>;
end;
end;
我尝试的第二种方法是使用一个通用字典来存储键值对,并提供注册和注销方法:
TRepository = class
private
FDictionary : TDictionary<string, TClass>;
public
constructor Create;
destructor Destroy; override;
function GetImplementation(const AClassName: string): IMyInterface;
procedure RegisterClass(AClass: TClass);
procedure UnregisterClass(AClass: TClass);
end;
在这里,我实现了GetImplementation方法如下:
function TRepository.GetImplementation(const AClassName: string): IMyInterface;
var
Obj : TObject;
begin
if FDictionary.ContainsKey(AClassName) then
begin
Obj := FDictionary[AClassName].Create;
Obj.GetInterface(IMyInterface, Result);
end;
end;
这个代码可以正常工作,我可以使用GetImplementation返回的值调用DoSomething方法,但它仍然存在内存泄漏问题; 在这里创建的Obj没有分配给任何接口变量; 因此,它没有引用计数,并且会泄漏。
.
现在,我的实际问题是:
所以我的问题是,如何安全地在运行时创建实现我的接口的类的实例? 我看到Delphi Spring Framework,在其Spring.Services单元中提供了这样的功能,但它有自己的反射例程和生命周期管理模型。 我正在寻找一个轻量级的解决方案,而不是整个第三方框架来为我完成这项工作。
谢谢