Spring4D - 如何从带有 TComponent 参数的容器解析为自动工厂
Spring4D - How to resolve from container with TComponent parameter to auto factory
举个例子,我想解决一个 class 传入 TComponent 和 TNotifyEvent 的问题,如下所示,但是 TObject 的基本构造函数被调用,而不是 TMy。
GlobalContainer.RegisterType<TMy>;
GlobalContainer.RegisterFactory<Func<TComponent,TNotifyEvent,TMy>>(TParamResolution.ByType);
var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
F(Self,Self.OnActivate);
我可以通过编写一些非常丑陋的代码来解决这个问题,但我认为这种解决方案很常见,我一定是做错了什么。
TOther = class
end;
TMy = class
public
constructor Create(C: TComponent; N: TNotifyEvent; O: TOther);
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
GlobalContainer.RegisterType<TOther>;
GlobalContainer.RegisterType<TMy>;
GlobalContainer.RegisterType<Func<TComponent,TNotifyEvent,TMy>>(
function: Func<TComponent,TNotifyEvent,TMy>
begin
Result:=Func<TComponent,TNotifyEvent,TMy>(
function(O: TComponent; N: TNotifyEVent): TMy
begin
Result:=TMy.Create(O,N,GlobalContainer.Resolve<TOther>);
end
);
end
);
GlobalContainer.Build;
var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
F(Self,Self.OnActivate);
end;
constructor TMy.Create(C: TComponent; N: TNotifyEvent; O: TOther);
begin
OutputDebugString('Resolved');
end;
在此先感谢您的指点。
这应该在开发中的最新提交后立即工作。
问题是类型化参数解析绑定到参数类型而不是参数类型。在这种情况下,这导致类型为 TForm2
的类型化值(取自被传递的参数)与类型 TComponent
的构造函数的 C 参数类型不匹配,因为该匹配检查类型标识而不是分配兼容性。
修复后,类型参数解析完全适用于工厂函数的参数类型,而不是可能(在对象的情况下)更窄的实际参数类型。
FWIW 供将来参考 - 手动注册工厂时,通常不需要使用 RegisterType
提供委托,但可以像这样直接使用 RegisterInstance
(请记住 Spring.Func<...> has
const`参数)当它没有任何捕获状态时:
GlobalContainer.RegisterInstance<Func<TComponent,TNotifyEvent,TMy>>(
function(const O: TComponent; const N: TNotifyEVent): TMy
begin
// ....
end);
编辑:我还为最佳参数分辨率默认值添加了自动检测。当工厂类型是 Spring.Func<...>
时,它会自动使用 ByType
,因此它可以从 RegisterFactory
调用中省略。对于所有其他类型,它像以前一样默认使用 ByName
。
举个例子,我想解决一个 class 传入 TComponent 和 TNotifyEvent 的问题,如下所示,但是 TObject 的基本构造函数被调用,而不是 TMy。
GlobalContainer.RegisterType<TMy>;
GlobalContainer.RegisterFactory<Func<TComponent,TNotifyEvent,TMy>>(TParamResolution.ByType);
var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
F(Self,Self.OnActivate);
我可以通过编写一些非常丑陋的代码来解决这个问题,但我认为这种解决方案很常见,我一定是做错了什么。
TOther = class
end;
TMy = class
public
constructor Create(C: TComponent; N: TNotifyEvent; O: TOther);
end;
procedure TForm2.Button1Click(Sender: TObject);
begin
GlobalContainer.RegisterType<TOther>;
GlobalContainer.RegisterType<TMy>;
GlobalContainer.RegisterType<Func<TComponent,TNotifyEvent,TMy>>(
function: Func<TComponent,TNotifyEvent,TMy>
begin
Result:=Func<TComponent,TNotifyEvent,TMy>(
function(O: TComponent; N: TNotifyEVent): TMy
begin
Result:=TMy.Create(O,N,GlobalContainer.Resolve<TOther>);
end
);
end
);
GlobalContainer.Build;
var F:=GlobalContainer.Resolve<Func<TComponent,TNotifyEvent,TMy>>;
F(Self,Self.OnActivate);
end;
constructor TMy.Create(C: TComponent; N: TNotifyEvent; O: TOther);
begin
OutputDebugString('Resolved');
end;
在此先感谢您的指点。
这应该在开发中的最新提交后立即工作。
问题是类型化参数解析绑定到参数类型而不是参数类型。在这种情况下,这导致类型为 TForm2
的类型化值(取自被传递的参数)与类型 TComponent
的构造函数的 C 参数类型不匹配,因为该匹配检查类型标识而不是分配兼容性。
修复后,类型参数解析完全适用于工厂函数的参数类型,而不是可能(在对象的情况下)更窄的实际参数类型。
FWIW 供将来参考 - 手动注册工厂时,通常不需要使用 RegisterType
提供委托,但可以像这样直接使用 RegisterInstance
(请记住 Spring.Func<...> has
const`参数)当它没有任何捕获状态时:
GlobalContainer.RegisterInstance<Func<TComponent,TNotifyEvent,TMy>>(
function(const O: TComponent; const N: TNotifyEVent): TMy
begin
// ....
end);
编辑:我还为最佳参数分辨率默认值添加了自动检测。当工厂类型是 Spring.Func<...>
时,它会自动使用 ByType
,因此它可以从 RegisterFactory
调用中省略。对于所有其他类型,它像以前一样默认使用 ByName
。