Spring4d-以接口和对象为参数的构造函数

798qvoo8  于 2022-10-16  发布在  Spring
关注(0)|答案(1)|浏览(124)

例如,我有3个这样的帧:

TBaseFrame = class(TFrame)
end;

TfraDataAwareEntity = class(TBaseFrame )
  private
    FEntity: TObject;
    procedure SetEntity(const Value: TObject);
    { Private declarations }
  public
    constructor Create(AOwner: TComponent;
                       ADataset: IDataset;
                       AEntity: TObject); 
    property Entity: TObject read FEntity write SetEntity;
  end;

TfraDataAwareEntityWithGrid = class(TBaseFrame )
  private
    FEntity: TObject;
    procedure SetEntity(const Value: TObject);
    { Private declarations }
  public
    constructor Create(AOwner: TComponent;
                       ADataset: IDataset;
                       AEntity: TObject); 
    property Entity: TObject read FEntity write SetEntity;
  end;

接口:

IDataset = interface
  ['{065771AA-A114-4D01-B180-427A39DD51D7}']
     procedure Save;
     procedure Load;
end;

实施:

TCustomDataset = class(TInterfacedObject, IDataset)
    procedure Save;
    procedure Load;
end;

注册:

GlobalContainer.RegisterType<TBaseFrame , TfraDataAwareEntity >
    ('TfraDataAwareEntity ');
 GlobalContainer.RegisterType<TBaseFrame , TfraDataAwareEntityWithGrid >
    ('TfraDataAwareEntityWithGrid ');
 GlobalContainer.RegisterType<TCustomDataset >.Implements<IDataset>.AsDefault;

现在我想创建一个框架:

GlobalContainer.Resolve<TBaseFrame>('TfraDataAwareEntity ',
      [ Self,
        GlobalContainer.Resolve<IDataset>,
        SomeObj ]);

上面代码的问题是,它不接受接口作为参数(错误:没有可以用这些参数调用的‘TContainer.Resolve<FrameUnit.TfraDataAwareEntity>’的重载版本),我需要传递TCustomDataset,但如果我有一个工厂返回IDataSet,我不能使用它,并且我不希望该单元与TCustomDataset耦合,只希望与IDataSet耦合。那么我该怎么做呢?
我尝试的另一种方法是在TfraDataAwareEntity构造函数(如下例:"Unsatisfied constructor" on constructor injection with Spring4D)上注入TCustomDataset,但随后我得到一个无法解析TComponent的错误,有没有办法在构造函数中注入IDataset中的TCustomDataset并传递其余参数?

f1tvaqid

f1tvaqid1#

您需要将值 Package 到TValue.From(...)中(您可以省略<..>中的特定类型,因为类型推断会处理它),因为

  • 在接受接口的TValue中没有隐式重载,因此公认具有误导性的编译器错误
  • SomeObj和SomeObj的隐式重载可能会导致非精确类型,这将导致构造函数查找失败。

我还建议您在容器中将其注册为工厂函数,以避免在您的消费者代码中发布代码--这不是依赖注入,而是服务定位器的反模式,因为您除了用Resolve调用交换构造函数调用外,什么也得不到。
您发布的代码中缺少的代码:

type
  TFrameFactory = reference to function(const AFrameName: string; AOwner: TComponent; AEntity: TObject): TBaseFrame;

  GlobalContainer.RegisterInstance<TFrameFactory>(
    function(const AFrameName: string; AOwner: TComponent; AEntity: TObject): TBaseFrame
    begin
      Result := GlobalContainer.Resolve<TBaseFrame>(AFrameName,
        [TValue.From(AOwner), TValue.From(GlobalContainer.Resolve<IDataset>), TValue.From(AEntity)]);
    end);

然后,您可以将TFrameFactory注入到您希望能够构建框架的组件中。
关于 Spring 的未来计划的注意事项:

  • 支持部分注入-这意味着当一个参数没有显式传递值时,容器知道如何解析自己(如IDataset),它将由容器自动解析,从而避免显式解析调用来提供所有参数。
  • 支持元信息--目前,您只能通过注册服务的名称来识别它们,这可能有点麻烦。这一功能将允许通过枚举之类的东西来识别它们。

相关问题