标签: spring4d

如何在Spring4d中从ServiceLocator获取子接口实例?

我是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?

谢谢.将愉快地提供额外的细节.

delphi spring4d

4
推荐指数
1
解决办法
431
查看次数

如何在Spring4D GlobalContainer中初始化主应用程序表单?

所以例如我有一个主窗体,并希望将一个记录器实例注入私有字段.

我注册了记录器

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变量.

delphi spring4d

4
推荐指数
1
解决办法
1449
查看次数

如何正确注入一个属性来形成?

我会在第二时间提出这个问题.请不要怪我.

情况:

我有一张表格

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)

delphi dependency-injection inversion-of-control spring4d

4
推荐指数
1
解决办法
1026
查看次数

Delphi使用可空类型进行模拟

使用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)

delphi mocking spring4d

3
推荐指数
1
解决办法
632
查看次数

无法获得Spring4D加密示例的预期结果

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)

抛开大/小写,它完全是一个不同的哈希.我知道一定是做错了,但是再没有使用的例子,所以我一直坚持如何做到这一点.

delphi hash cryptography spring4d

3
推荐指数
1
解决办法
364
查看次数

在Spring4D中调用GlobalContainer.Resolve时,如何将字符串值作为参数传递?

使用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)

delphi dependency-injection ioc-container spring4d

3
推荐指数
1
解决办法
841
查看次数

使用Spring4D构造函数注入"不满意的构造函数"

我正在努力使用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)

delphi spring4d

3
推荐指数
1
解决办法
500
查看次数

如何实现具有IsFirst和IsLast函数的枚举器?

我正在使用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功能?

delphi enumerator spring4d delphi-xe7

3
推荐指数
1
解决办法
314
查看次数

我为什么要使用TCollections.CreateList <T>而不是TList <T> .Create

我将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 ...但那是另一个故事.

delphi spring4d

3
推荐指数
1
解决办法
540
查看次数

如何使用参数调用 TEvent 的简单示例

我正在尝试将 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)

delphi spring4d

3
推荐指数
1
解决办法
144
查看次数