Jacek Laskowski 57 Posted December 19, 2019 I have problem with one factory. definition TSQLDataSuiteWorkerMethod = procedure(const aDataSuite : ISQLDataSuite) of object; TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite) [...] public constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean = True; const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil; const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); reintroduce; end; {$M+} TSQLDataSuiteFactory = reference to function(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean = True; const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil; const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil): ISQLDataSuite; {$M-} container registration aContainer.RegisterType<TSQLDataSuite>.Implements<ISQLDataSuite>; aContainer.RegisterFactory<TSQLDataSuiteFactory>; resolve in code: fSQLDataSuiteFactory : TSQLDataSuiteFactory; var Data: ISQLDataSuite; begin Data := fSQLDataSuiteFactory('TableName', TModifyingSQLKind.SQLInsert, True, nil, nil); And after last l get exception from Spring4D: Unsatisfied constructor on TSQLDataSuite What have I forgotten? I use in the program dozens of factories, classes and interfaces, all based on the spring container, everything works correctly, only this case I cannot understand. ps. maybe it's worth opening a subforum for Spring4D? Share this post Link to post
Stefan Glienke 2002 Posted December 19, 2019 When looking for the correct constructor to match the algo tries to match the parameters given with the parameters required by the constructor. However it does not allow injecting nil which is the reason it does not consider this constructor. As for a subforum - there is already a forum for Spring4D at https://groups.google.com/forum/#!forum/spring4d Share this post Link to post
Jacek Laskowski 57 Posted December 20, 2019 I add new constructor to TSQLDataSuite: constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean); overload; And new factory: ISQLDataSuiteFactory = interface(IInvokable) ['{A101FA06-ED33-478A-9066-821BC8C5E2AE}'] function Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean ): ISQLDataSuite; overload; function Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean; const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod; const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod): ISQLDataSuite; overload; end; but after call: var fSQLDataSuiteFactory : ISQLDataSuiteFactory; [...] lData := fSQLDataSuiteFactory.Create('TableName', TModifyingSQLKind.SQLInsert, True); I stiil get exception: Unsatisfied constructor on type: TSQLDataSuite How to do it right? Share this post Link to post
Jacek Laskowski 57 Posted December 20, 2019 When I comment on one of the constructors, then the factory was working properly. TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite) [...] public // constructor Create(const aTableName: RawByteString; // const aSQLKind: TModifyingSQLKind; // const aProcessSQL : Boolean = True; // const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil; // const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); overload; constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean); overload; end; There is a problem with factory when a class has two active constructors. But I can't understand it. Share this post Link to post
Stefan Glienke 2002 Posted December 20, 2019 Then you are doing something wrong - can't repro {$APPTYPE CONSOLE} uses Spring.Container; type TModifyingSQLKind = (SQLInsert); TSQLDataSuiteWorkerMethod = procedure of object; ISQLDataSuite = interface ['{068D3552-CBA6-4AAE-9061-59FA6407FF8C}'] end; TSQLDataSuite = class(TInterfacedObject, ISQLDataSuite) public constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean); overload; constructor Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean = True; const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod = nil; const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod = nil); overload; end; ISQLDataSuiteFactory = interface(IInvokable) ['{A101FA06-ED33-478A-9066-821BC8C5E2AE}'] function Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean ): ISQLDataSuite; overload; function Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL : Boolean; const aBeforeWorkerMethod: TSQLDataSuiteWorkerMethod; const aAfterWorkerMethod: TSQLDataSuiteWorkerMethod): ISQLDataSuite; overload; end; { TSQLDataSuite } constructor TSQLDataSuite.Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL: Boolean); begin Writeln('create'); end; constructor TSQLDataSuite.Create(const aTableName: RawByteString; const aSQLKind: TModifyingSQLKind; const aProcessSQL: Boolean; const aBeforeWorkerMethod, aAfterWorkerMethod: TSQLDataSuiteWorkerMethod); begin end; var fSQLDataSuiteFactory: ISQLDataSuiteFactory; begin globalContainer.RegisterType<TSQLDataSuite>.Implements<ISQLDataSuite>; globalContainer.RegisterFactory<ISQLDataSuiteFactory>(); globalContainer.Build; fSQLDataSuiteFactory := globalContainer.Resolve<ISQLDataSuiteFactory>(); fSQLDataSuiteFactory.Create('TableName', TModifyingSQLKind.SQLInsert, True); Readln; end. Share this post Link to post
Jacek Laskowski 57 Posted December 23, 2019 @Stefan Glienke Your example works, my code doesn't. It's identical*. I spent a lot of hours and energy modifying the code from left to right... I finally found it! Please add a line in your example before registering classes in the container: globalContainer.AddExtension<TActivatorContainerExtension>; and then check it out... 🙂 I'm very tired of it... give me a tip how to fix it, please. * - almost Share this post Link to post
Stefan Glienke 2002 Posted December 23, 2019 Write your own ConstructorSelector that does not want the one with the most parameters. 1 Share this post Link to post
Jacek Laskowski 57 Posted December 23, 2019 What is ConstructorSelector? I didn't find anything in Spring4D sources or google. Give me a simple example, please. Share this post Link to post
Stefan Glienke 2002 Posted December 23, 2019 Look into TActivatorContainerExtension Share this post Link to post
Jacek Laskowski 57 Posted December 24, 2019 I think you mean this piece of code (from the SelectEligibleConstructor method): end).TakeWhile( function(const injection: IInjection): Boolean begin if maxCount = -1 then maxCount := injection.DependencyCount; if targetType = nil then targetType := injection.Target.Parent; Result := (injection.DependencyCount = maxCount) and (targetType = injection.Target.Parent); end).Where(... But how (at this point) to get to the list of arguments and their types to choose the right constructor? Share this post Link to post