我是Spring4D框架中的新手并请求帮助.
我有下一个类和接口:
ICommand = interface
TCommand = class(TInterfacedObject, ICommand)
IVecadCommand = interface(ICommand)
TVecadCommand = class(TCommand, IVecadCommand)
TVecadCommandJPG = class(TVecadCommand, IVecadCommand)
TCommandDeckelJPG = class(TVecadCommandJPG, IVecadCommand)
Run Code Online (Sandbox Code Playgroud)
然后我注册一个组件:
GlobalContainer.RegisterComponent<TCommandDeckelJPG>.Implements<IVecadCommand>('deckel_jpg');
Run Code Online (Sandbox Code Playgroud)
然后我尝试在ServiceLocator的帮助下创建一个对象:
var
i: Integer;
com: ICommand;
begin
Result := nil;
com := ServiceLocator.GetService<ICommand>(actionName);
com.setSession(designSession);
Result := com;
end;
Run Code Online (Sandbox Code Playgroud)
作为执行的结果,我有一个例外:
Invalid class typecast
Run Code Online (Sandbox Code Playgroud)
为了避免异常,我这样做:
var
i: Integer;
com: IVecadCommand;
begin
Result := nil;
com := ServiceLocator.GetService<IVecadCommand>(actionName);
com.setSession(designSession);
Result := com;
end;
Run Code Online (Sandbox Code Playgroud)
一切都好.
要点是我必须在这种情况下使用TContainer作为TCommand的Repository和继承的类.所以我必须先使用ServiceLocator.
我该怎么做才能避免异常并在TContainer中使用ICommand而不是IVecadCommand?
谢谢.将愉快地提供额外的细节.
所以例如我有一个主窗体,并希望将一个记录器实例注入私有字段.
我注册了记录器
GlobalContainer.RegisterType<TCNHInMemoryLogger>.Implements<ILogger>;
Run Code Online (Sandbox Code Playgroud)
我的主要表格中有一个私人字段
private
FLogger: ILogger;
Run Code Online (Sandbox Code Playgroud)
所有我想要的是这样做:
private
[Inject]
FLogger: ILogger;
Run Code Online (Sandbox Code Playgroud)
在我的DPR文件中,我有典型的delphi方式来创建主窗体:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(Tfrm_CNH, frm_CNH);
Application.Run;
end.
Run Code Online (Sandbox Code Playgroud)
在表单创建方式中我应该更改哪些内容可以正确注入私有字段?
顺便说一句,如果我使用GlobalContainer.Resolve解决Form.OnCreate中的字段,它可以正常工作.但我想避免在表单中使用GlobalContainer变量.
我会在第二时间提出这个问题.请不要怪我.
情况:
我有一张表格
TfrmMain = class(TForm)
private
[Inject('IniFileSettings')]
FSettings: ISettings;
public
end;
Run Code Online (Sandbox Code Playgroud)
我有容器初始化程序:
procedure BuildContainer(const container: TContainer);
begin
container.RegisterType<TIniSettings>.Implements<ISettings>('IniFileSettings');
container.RegisterType<TfrmMain, TfrmMain>.DelegateTo(
function: TfrmMain
begin
Application.CreateForm(TfrmMain, Result);
end);
container.Build;
end;
Run Code Online (Sandbox Code Playgroud)
所以我通过容器初始化TfrmMain和TIniSettings.
在.DPR我有:
begin
BuildContainer(GlobalContainer);
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
Run Code Online (Sandbox Code Playgroud)
我还有TApplication的助手:
procedure TApplicationHelper.CreateForm(InstanceClass: TComponentClass; var Reference);
var
locator: IServiceLocator;
begin
locator := TServiceLocatorAdapter.Create(GlobalContainer);
if locator.HasService(InstanceClass.ClassInfo) then
TObject(Reference) := GlobalContainer.Resolve(InstanceClass.ClassInfo).AsObject
else
inherited CreateForm(InstanceClass, Reference);
end;
Run Code Online (Sandbox Code Playgroud)
问题:当我尝试时
procedure TfrmMain.FormCreate(Sender: TObject);
begin
s := FSettings.ReadString('Connection', 'Server', 'localhost');
end;
Run Code Online (Sandbox Code Playgroud)
我得到AV异常,因为FSettings目前是NIL.
从容器中获取FSettings对象的正确方法是什么?
更新:
FSettings …Run Code Online (Sandbox Code Playgroud) 使用Spring框架中的Nullable类型设置Delphi DSharp模拟的最佳方法是什么?我尝试了各种方法,我知道我可能遗漏了一些非常简陋的东西,但我无法弄清楚如何让以下代码工作:
program DSharkMockNullable;
{$APPTYPE CONSOLE}
{$R *.res}
uses
DSharp.Testing.Mock,
Spring,
System.SysUtils;
type
{$M+}
IBaseMock = interface
['{B3311345-3C1F-47E3-8235-57B1BA04E957}']
function GetId: TNullableInteger;
procedure SetId(Value: TNullableInteger);
property Id: TNullableInteger read GetId write SetId;
end;
{$M+}
IMockMe = interface(IBaseMock)
['{07F8F233-E8F5-4743-88C5-97A66BB01E29}']
function GetObjectId: TNullableInteger;
procedure SetObjectId(Value: TNullableInteger);
property ObjectId: TNullableInteger read GetObjectId write SetObjectId;
function GetObjectName: TNullableString;
procedure SetObjectName(Value: TNullableString);
property ObjectName: TNullableString read GetObjectName write SetObjectName;
end;
TMyObject = class
public
function ObjectIdAsString(const AObject: IMockMe): string;
end;
{ TMyObject }
function TMyObject.ObjectIdAsString(const AObject: …Run Code Online (Sandbox Code Playgroud) Spring4D库有加密类,但我无法按预期工作.我可能错误地使用它们,但是缺少任何示例都会让它变得困难.
例如,在网站https://quickhash.com/hash-sha256-online上,我可以散列单词"test"来生成以下哈希:
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
Run Code Online (Sandbox Code Playgroud)
使用Spring4D库,以下代码生成不同的哈希:
CreateSHA256.ComputeHash('test').ToString;
Run Code Online (Sandbox Code Playgroud)
结果是:
9EFEA1AEAC9EDA04A892885A65FDAE0E6D9BE8C9FC96DA76D31B929262E12B1D
Run Code Online (Sandbox Code Playgroud)
抛开大/小写,它完全是一个不同的哈希.我知道一定是做错了,但是再没有使用的例子,所以我一直坚持如何做到这一点.
使用Spring4D时,如何在调用GlobalContainer时将字符串值作为参数传递.解析,以便在已解析的类构造函数上使用此字符串值?
我想解决映射到TWorker的类IWorker.TWorker类在它的构造函数中依赖于ITool加上工作者名称的字符串.
我猜的答案在于TValue数组,它可以作为GlobalContainer.Resolve的参数给出,但我不明白如何使用它.
我发现这篇文章关于在调用可能有效的GlobalContainer.Resolve时使用TParameterOverride作为参数,但这个功能似乎已经在Spring4D的1.1版本中消失了.
我想在注册我的类型时避免调用InjectConstructor.
我需要帮助的部分是
GlobalContainer.Resolve<IWorker>([{what do I put here?}]).Work;
Run Code Online (Sandbox Code Playgroud)
这是我的一个小项目
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Spring.Container;
type
IWorker = interface
['{2BBD7E9C-4806-4F01-9B05-9E9DD928D21D}']
procedure Work;
end;
ITool = interface
['{F962209D-4BC3-41C4-9089-0A874632ED1A}']
procedure Use;
end;
TWorker = class(TInterfacedObject, IWorker)
private
FTool: ITool;
FName: string;
procedure Work;
public
constructor Create(tool: ITool; name: string);
end;
THammer = class(TInterfacedObject, ITool)
private
procedure Use;
end;
{ TWorker }
constructor TWorker.Create(tool: ITool; name: string);
begin
FTool := tool;
FName := name;
end; …Run Code Online (Sandbox Code Playgroud) 我正在努力使用Spring4D的构造函数注入.在某个类中,我想将一个接口的特定实现(按名称)注入构造函数中.
看这个:
IListFactory = interface
['{40...29}']
function GetList : IListOfSomething;
end;
ICiderPress = interface
['{50...10}']
procedure Press;
end;
TAppleListFactory = class(TInterfacedObject, IListFactory)
function GetList : IListOfSomething;
end;
TCiderPress = class(TInterfacedObject, ICiderPress)
private
FListFactory : IListFactory;
public
constructor Create(const ListFactory : IListFactory);
procedure Press;
end;
implementation
function TCiderPress.Create(const ListFactory : IListFactory);
begin
FListFactory := ListFactory;
end;
procedure TCiderPress.Press;
begin
// Do somtihing with FListFactory
end;
initialization
GlobalContainer.RegisterType<TAppleListFactory>.Implements<IListFactory>('apple');
GlobalContainer.RegisterType<TCiderPress>.Implements<ICiderPress>;
end.
Run Code Online (Sandbox Code Playgroud)
现在我使用ServiceLocator获取我的印刷机实例:
CiderPress := ServiceLocator.GetService<ICiderPress>;
CiderPress.Press;
Run Code Online (Sandbox Code Playgroud)
它工作正常.
现在我添加第二个ListFactory:
TOrangeListFactory = class(TInterfacedObject, IListFactory)
function …Run Code Online (Sandbox Code Playgroud) 我正在使用Spring4D进行所有收藏.
现在有一种情况我必须知道枚举器的当前值是集合中的第一个(很容易)还是最后一个(很难).
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Spring.Collections;
var
Enumerable: IEnumerable<Integer>;
Enumerator: IEnumerator<Integer>;
begin
Enumerable := TEnumerable.Query<Integer>(TArray<Integer>.Create(1, 2, 3, 4, 5)
) as IEnumerable<Integer>;
Enumerator := Enumerable.GetEnumerator;
while Enumerator.MoveNext do
begin
WriteLn('Value = ', Enumerator.Current);
WriteLn('First in collection? ', Enumerator.CurrentIsFirst);
WriteLn('Last in collection? ', Enumerator.CurrentIsLast);
end;
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)
CurrentIsFirst 可以使用本地布尔值实现,该布尔值在第一个值通过后重置.
但是,我不知道一种简单的实施方法CurrentIsLast.
它应该能够处理延迟集合,因为它们可能包含太多值以适应内存.
我该如何实现这样的CurrentIsLast功能?
我将map(),reduce()和where(qlint:string)添加到我的Spring4D分支中.当我编写这些函数时,我发现列表的行为在以不同方式创建时存在差异.
如果我用TList<TSomeClass>.create枚举中的对象创建它们的类型TSomeClass.
如果我用TCollections.CreateList<TSomeClass>枚举中的对象创建它们的类型TObject.
所以问题是:
使用是否存在缺点TList<TSomeClass>.create?
换句话说:我为什么要用TCollections.CreateList<TSomeClass>?
顺便说一句:使用TCollections.CreateList我有一个TObjectList而不是TList.所以它应该被称为TCollections.CreateObjectList ...但那是另一个故事.
我正在尝试将 Spring4d 框架用于 Delphi,并且我想使用多播事件。在使用“正常”TNotifyEvent 时,它可以工作并且处理程序将被调用两次。
uses
...
Spring,
Spring.Events,
Spring.Events.Base;
procedure TfrmMain.EventHandler1(Sender: TObject);
begin
Log('called handler1');
end;
procedure TfrmMain.btnNotifyEventClick(Sender: TObject);
var
MulticastEvent: TEvent<TNotifyEvent>;
begin
MulticastEvent := TEvent<TNotifyEvent>.Create;
try
MulticastEvent.Add(EventHandler1);
MulticastEvent.Add(EventHandler1);
MulticastEvent.Add(EventHandler1);
MulticastEvent.Remove(EventHandler1);
MulticastEvent.Invoke;
finally
MulticastEvent.Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
但我不知道如何将这些 Multicast 事件与我自己的 Event 一起使用TSyncEvent。EventHandler2 需要一个字符串。所以我想用文本调用 Invoke 方法。
type
TSyncEvent = procedure(Sender: TObject; const iMsg: string) of object;
procedure TfrmMain.EventHandler2(Sender: TObject; const iMsg: string);
begin
Log('called handler2: '+iMsg);
end;
procedure TfrmMain.btnSyncEventClick(Sender: TObject);
var
MulticastEvent: TEvent<TSyncEvent>;
begin
MulticastEvent := TEvent<TSyncEvent>.Create;
try
MulticastEvent.Add(EventHandler2); …Run Code Online (Sandbox Code Playgroud)