gpt4 book ai didi

delphi - 在运行时创建接口(interface)实现者实例

转载 作者:行者123 更新时间:2023-12-03 14:41:16 26 4
gpt4 key购买 nike

首先,稍微解释一下我的情况:

我有一个由不同类实现的示例接口(interface),并且这些类可能并不总是具有共享的祖先:

  IMyInterface = interface
['{1BD8F7E3-2C8B-4138-841B-28686708DA4D}']
procedure DoSomething;
end;

TMyImpl = class(TInterfacedPersistent, IMyInterface)
procedure DoSomething;
end;

TMyImp2 = class(TInterfacedObject, IMyInterface)
procedure DoSomething;
end;

我还有一个工厂方法,它应该创建一个实现我的接口(interface)的对象的实例。我的工厂方法接收类名作为其参数:

  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。更重要的是,创建的对象并没有分配给接口(interface)变量;因此,它会被泄露。我还尝试使用 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没有赋值给任何接口(interface)变量;因此,它不是引用计数的,并且是泄漏的。

.

现在,我的实际问题:

所以我的问题是,如何安全地创建在运行时实现我的接口(interface)的类的实例?我看到了 Delphi Spring Framework,它在 Spring.Services 单元中提供了此类功能,但它有自己的反射例程和生命周期管理模型。我正在寻找一个轻量级的解决方案,而不是一个完整的第三方框架来为我做到这一点。

问候

最佳答案

第一种使用 RTTI 的情况会导致访问冲突,因为 TRttiContext.FindType(AClassName) 无法找到未在应用程序中显式注册或使用的类的 Rtti 信息。

所以你可以将代码更改为

function GetImplementation(AClass: TClass): IMyInterface;
var
ctx : TRttiContext;
t : TRttiInstanceType;
begin
t := ctx.GetType(AClass).AsInstance;
if Assigned(t) then
Result := t.GetMethod('Create').Invoke(t.MetaclassType, []).AsInterface As IMyInterface;
end;

并以这种方式调用

AClass:=GetImplementation(TMyImp2);

现在,如果您想使用类名称来调用该类,则使用列表(如 TRepository 类)来注册类是一种有效的方法。关于内存泄漏,我很确定这是由于 TMyImpl 类派生自 TInterfacedPersistent 造成的,它不像 TInterfacedObject 那样直接实现引用计数>.

TRepository 的此实现必须正常工作。

constructor TRepository.Create;
begin
FDictionary:=TDictionary<string,TClass>.Create;
end;

destructor TRepository.Destroy;
begin
FDictionary.Free;
inherited;
end;

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;

{
or using the RTTI
var
ctx : TRttiContext;
t : TRttiInstanceType;
begin
t := ctx.GetType(FDictionary[AClassName]).AsInstance;
if Assigned(t) then
Result := t.GetMethod('Create').Invoke(t.MetaclassType, []).AsInterface As IMyInterface;
end;
}

procedure TRepository.RegisterClass(AClass: TClass);
begin
FDictionary.Add(AClass.ClassName,AClass);
end;

procedure TRepository.UnregisterClass(AClass: TClass);
begin
FDictionary.Remove(AClass.ClassName);
end;

关于delphi - 在运行时创建接口(interface)实现者实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8158035/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com