Quick.IOC.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. { ***************************************************************************
  2. Copyright (c) 2016-2022 Kike Pérez
  3. Unit : Quick.IoC
  4. Description : IoC Dependency Injector
  5. Author : Kike Pérez
  6. Version : 1.0
  7. Created : 19/10/2019
  8. Modified : 19/01/2022
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.IoC;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. System.SysUtils,
  26. RTTI,
  27. {$IFDEF DEBUG_IOC}
  28. Quick.Debug.Utils,
  29. {$ENDIF}
  30. System.TypInfo,
  31. System.Generics.Collections,
  32. Quick.Logger.Intf,
  33. Quick.Options;
  34. type
  35. TActivatorDelegate<T> = reference to function: T;
  36. TIocRegistration = class
  37. type
  38. TRegisterMode = (rmTransient, rmSingleton, rmScoped);
  39. private
  40. fName : string;
  41. fRegisterMode : TRegisterMode;
  42. fIntfInfo : PTypeInfo;
  43. fImplementation : TClass;
  44. fActivatorDelegate : TActivatorDelegate<TValue>;
  45. public
  46. constructor Create(const aName : string);
  47. property Name : string read fName;
  48. property IntfInfo : PTypeInfo read fIntfInfo write fIntfInfo;
  49. property &Implementation : TClass read fImplementation write fImplementation;
  50. function IsSingleton : Boolean;
  51. function IsTransient : Boolean;
  52. function IsScoped : Boolean;
  53. function AsSingleton : TIocRegistration;
  54. function AsTransient : TIocRegistration;
  55. function AsScoped : TIocRegistration;
  56. property ActivatorDelegate : TActivatorDelegate<TValue> read fActivatorDelegate write fActivatorDelegate;
  57. end;
  58. TIocRegistrationInterface = class(TIocRegistration)
  59. private
  60. fInstance : IInterface;
  61. public
  62. property Instance : IInterface read fInstance write fInstance;
  63. end;
  64. TIocRegistrationInstance = class(TIocRegistration)
  65. private
  66. fInstance : TObject;
  67. public
  68. property Instance : TObject read fInstance write fInstance;
  69. end;
  70. TIocRegistration<T> = record
  71. private
  72. fRegistration : TIocRegistration;
  73. public
  74. constructor Create(aRegistration : TIocRegistration);
  75. function AsSingleton : TIocRegistration<T>;
  76. function AsTransient : TIocRegistration<T>;
  77. function AsScoped : TIocRegistration<T>;
  78. function DelegateTo(aDelegate : TActivatorDelegate<T>) : TIocRegistration<T>;
  79. end;
  80. IIocRegistrator = interface
  81. ['{F3B79B15-2874-4B66-9B7F-06E2EBFED1AE}']
  82. function GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
  83. function RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
  84. function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  85. end;
  86. TIocRegistrator = class(TInterfacedObject,IIocRegistrator)
  87. private
  88. fDependencies : TDictionary<string,TIocRegistration>;
  89. fDependencyOrder : TList<TIocRegistration>;
  90. public
  91. constructor Create;
  92. destructor Destroy; override;
  93. property Dependencies : TDictionary<string,TIocRegistration> read fDependencies write fDependencies;
  94. property DependencyOrder : TList<TIocRegistration> read fDependencyOrder;
  95. function IsRegistered<TInterface: IInterface; TImplementation: class>(const aName : string = '') : Boolean; overload;
  96. function IsRegistered<T>(const aName : string = '') : Boolean; overload;
  97. function GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
  98. function RegisterType<TInterface: IInterface; TImplementation: class>(const aName : string = '') : TIocRegistration<TImplementation>; overload;
  99. function RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration; overload;
  100. function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration; overload;
  101. function RegisterInstance<T : class>(const aName : string = '') : TIocRegistration<T>; overload;
  102. function RegisterInstance<TInterface : IInterface>(aInstance : TInterface; const aName : string = '') : TIocRegistration; overload;
  103. function RegisterOptions<T : TOptions>(aOptions : T) : TIocRegistration<T>;
  104. end;
  105. IIocContainer = interface
  106. ['{6A486E3C-C5E8-4BE5-8382-7B9BCCFC1BC3}']
  107. function RegisterType(aInterface: PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
  108. function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  109. function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
  110. procedure Build;
  111. end;
  112. IIocInjector = interface
  113. ['{F78E6BBC-2A95-41C9-B231-D05A586B4B49}']
  114. end;
  115. TIocInjector = class(TInterfacedObject,IIocInjector)
  116. end;
  117. IIocResolver = interface
  118. ['{B7C07604-B862-46B2-BF33-FF941BBE53CA}']
  119. function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
  120. end;
  121. TIocResolver = class(TInterfacedObject,IIocResolver)
  122. private
  123. fRegistrator : TIocRegistrator;
  124. fInjector : TIocInjector;
  125. function CreateInstance(aClass : TClass) : TValue;
  126. public
  127. constructor Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
  128. function Resolve<T>(const aName : string = ''): T; overload;
  129. function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
  130. function ResolveAll<T>(const aName : string = '') : TList<T>;
  131. end;
  132. TTypedFactory<T : class, constructor> = class(TVirtualInterface)
  133. private
  134. fResolver : TIocResolver;
  135. public
  136. constructor Create(PIID: PTypeInfo; aResolver : TIocResolver);
  137. procedure DoInvoke(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
  138. end;
  139. IFactory<T> = interface
  140. ['{92D7AB4F-4C0A-4069-A821-B057E193DE65}']
  141. function New : T;
  142. end;
  143. TSimpleFactory<T : class, constructor> = class(TInterfacedObject,IFactory<T>)
  144. private
  145. fResolver : TIocResolver;
  146. public
  147. constructor Create(aResolver : TIocResolver);
  148. function New : T;
  149. end;
  150. TSimpleFactory<TInterface : IInterface; TImplementation : class, constructor> = class(TInterfacedObject,IFactory<TInterface>)
  151. private
  152. fResolver : TIocResolver;
  153. public
  154. constructor Create(aResolver : TIocResolver);
  155. function New : TInterface;
  156. end;
  157. TIocContainer = class(TInterfacedObject,IIocContainer)
  158. private
  159. fRegistrator : TIocRegistrator;
  160. fResolver : TIocResolver;
  161. fInjector : TIocInjector;
  162. fLogger : ILogger;
  163. class var
  164. GlobalInstance: TIocContainer;
  165. protected
  166. class constructor Create;
  167. class destructor Destroy;
  168. public
  169. constructor Create;
  170. destructor Destroy; override;
  171. function IsRegistered<TInterface: IInterface; TImplementation: class>(const aName: string): Boolean; overload;
  172. function IsRegistered<TInterface : IInterface>(const aName: string): Boolean; overload;
  173. function RegisterType<TInterface: IInterface; TImplementation: class>(const aName : string = '') : TIocRegistration<TImplementation>; overload;
  174. function RegisterType(aInterface: PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration; overload;
  175. function RegisterInstance<T : class>(const aName: string = ''): TIocRegistration<T>; overload;
  176. function RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration; overload;
  177. function RegisterInstance<TInterface : IInterface>(aInstance : TInterface; const aName : string = '') : TIocRegistration; overload;
  178. function RegisterOptions<T : TOptions>(aOptions : TOptions) : TIocRegistration<T>; overload;
  179. function RegisterOptions<T : TOptions>(aOptions : TConfigureOptionsProc<T>) : TIocRegistration<T>; overload;
  180. function Resolve<T>(const aName : string = ''): T; overload;
  181. function Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue; overload;
  182. function ResolveAll<T>(const aName : string = '') : TList<T>;
  183. function AbstractFactory<T : class, constructor>(aClass : TClass) : T; overload;
  184. function AbstractFactory<T : class, constructor> : T; overload;
  185. function RegisterTypedFactory<TFactoryInterface : IInterface; TFactoryType : class, constructor>(const aName : string = '') : TIocRegistration<TTypedFactory<TFactoryType>>;
  186. function RegisterSimpleFactory<TInterface : IInterface; TImplementation : class, constructor>(const aName : string = '') : TIocRegistration;
  187. procedure Build;
  188. end;
  189. TIocServiceLocator = class
  190. public
  191. class function GetService<T> : T;
  192. class function TryToGetService<T: IInterface>(aService : T) : Boolean;
  193. end;
  194. Name = class(TCustomAttribute)
  195. private
  196. fName: string;
  197. public
  198. constructor Create(aName: string);
  199. property Name: String read fName;
  200. end;
  201. EIocRegisterError = class(Exception);
  202. EIocResolverError = class(Exception);
  203. EIocBuildError = class(Exception);
  204. //singleton global instance
  205. function GlobalContainer : TIocContainer;
  206. function ServiceLocator : TIocServiceLocator;
  207. implementation
  208. function GlobalContainer: TIocContainer;
  209. begin
  210. Result := TIocContainer.GlobalInstance;
  211. end;
  212. function ServiceLocator : TIocServiceLocator;
  213. begin
  214. Result := TIocServiceLocator.Create;
  215. end;
  216. { TIocRegistration }
  217. constructor TIocRegistration.Create;
  218. begin
  219. fRegisterMode := TRegisterMode.rmTransient;
  220. end;
  221. function TIocRegistration.AsTransient: TIocRegistration;
  222. begin
  223. Result := Self;
  224. fRegisterMode := TRegisterMode.rmTransient;
  225. end;
  226. function TIocRegistration.AsSingleton : TIocRegistration;
  227. begin
  228. Result := Self;
  229. fRegisterMode := TRegisterMode.rmSingleton;
  230. end;
  231. function TIocRegistration.AsScoped: TIocRegistration;
  232. begin
  233. Result := Self;
  234. fRegisterMode := TRegisterMode.rmScoped;
  235. end;
  236. function TIocRegistration.IsTransient: Boolean;
  237. begin
  238. Result := fRegisterMode = TRegisterMode.rmTransient;
  239. end;
  240. function TIocRegistration.IsSingleton: Boolean;
  241. begin
  242. Result := fRegisterMode = TRegisterMode.rmSingleton;
  243. end;
  244. function TIocRegistration.IsScoped: Boolean;
  245. begin
  246. Result := fRegisterMode = TRegisterMode.rmScoped;
  247. end;
  248. { TIocContainer }
  249. class constructor TIocContainer.Create;
  250. begin
  251. GlobalInstance := TIocContainer.Create;
  252. end;
  253. class destructor TIocContainer.Destroy;
  254. begin
  255. if GlobalInstance <> nil then GlobalInstance.Free;
  256. inherited;
  257. end;
  258. function TIocContainer.AbstractFactory<T>(aClass: TClass): T;
  259. begin
  260. Result := fResolver.CreateInstance(aClass).AsType<T>;
  261. end;
  262. function TIocContainer.AbstractFactory<T> : T;
  263. begin
  264. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  265. end;
  266. procedure TIocContainer.Build;
  267. var
  268. dependency : TIocRegistration;
  269. begin
  270. {$IFDEF DEBUG_IOC}
  271. TDebugger.TimeIt(Self,'Build','Container dependencies building...');
  272. {$ENDIF}
  273. for dependency in fRegistrator.DependencyOrder do
  274. begin
  275. try
  276. {$IFDEF DEBUG_IOC}
  277. TDebugger.Trace(Self,'[Building container]: %s',[dependency.fIntfInfo.Name]);
  278. {$ENDIF}
  279. if dependency.IsSingleton then fResolver.Resolve(dependency.fIntfInfo,dependency.Name);
  280. {$IFDEF DEBUG_IOC}
  281. TDebugger.Trace(Self,'[Built container]: %s',[dependency.fIntfInfo.Name]);
  282. {$ENDIF}
  283. except
  284. on E : Exception do raise EIocBuildError.CreateFmt('Build Error on "%s(%s)" dependency: %s!',[dependency.fImplementation.ClassName,dependency.Name,e.Message]);
  285. end;
  286. end;
  287. end;
  288. constructor TIocContainer.Create;
  289. begin
  290. fLogger := nil;
  291. fRegistrator := TIocRegistrator.Create;
  292. fInjector := TIocInjector.Create;
  293. fResolver := TIocResolver.Create(fRegistrator,fInjector);
  294. end;
  295. destructor TIocContainer.Destroy;
  296. begin
  297. fInjector.Free;
  298. fResolver.Free;
  299. fRegistrator.Free;
  300. fLogger := nil;
  301. inherited;
  302. end;
  303. function TIocContainer.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
  304. begin
  305. Result := fRegistrator.IsRegistered<TInterface,TImplementation>(aName);
  306. end;
  307. function TIocContainer.IsRegistered<TInterface>(const aName: string): Boolean;
  308. begin
  309. Result := fRegistrator.IsRegistered<TInterface>(aName);
  310. end;
  311. function TIocContainer.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
  312. begin
  313. Result := fRegistrator.RegisterType<TInterface, TImplementation>(aName);
  314. end;
  315. function TIocContainer.RegisterType(aInterface: PTypeInfo; aImplementation: TClass; const aName: string): TIocRegistration;
  316. begin
  317. Result := fRegistrator.RegisterType(aInterface,aImplementation,aName);
  318. end;
  319. function TIocContainer.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
  320. begin
  321. Result := fRegistrator.RegisterInstance<T>(aName);
  322. end;
  323. function TIocContainer.RegisterTypedFactory<TFactoryInterface,TFactoryType>(const aName: string): TIocRegistration<TTypedFactory<TFactoryType>>;
  324. begin
  325. Result := fRegistrator.RegisterType<TFactoryInterface,TTypedFactory<TFactoryType>>(aName).DelegateTo(function : TTypedFactory<TFactoryType>
  326. begin
  327. Result := TTypedFactory<TFactoryType>.Create(TypeInfo(TFactoryInterface),fResolver);
  328. end);
  329. end;
  330. function TIocContainer.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  331. begin
  332. Result := fRegistrator.RegisterInstance(aTypeInfo,aName);
  333. end;
  334. function TIocContainer.RegisterInstance<TInterface>(aInstance: TInterface; const aName: string): TIocRegistration;
  335. begin
  336. Result := fRegistrator.RegisterInstance<TInterface>(aInstance,aName);
  337. end;
  338. function TIocContainer.RegisterOptions<T>(aOptions: TOptions): TIocRegistration<T>;
  339. begin
  340. Result := fRegistrator.RegisterOptions<T>(aOptions).AsSingleton;
  341. end;
  342. function TIocContainer.RegisterOptions<T>(aOptions: TConfigureOptionsProc<T>): TIocRegistration<T>;
  343. var
  344. options : T;
  345. begin
  346. options := T.Create;
  347. aOptions(options);
  348. Result := Self.RegisterOptions<T>(options);
  349. end;
  350. function TIocContainer.RegisterSimpleFactory<TInterface, TImplementation>(const aName: string): TIocRegistration;
  351. begin
  352. Result := fRegistrator.RegisterInstance<IFactory<TInterface>>(TSimpleFactory<TInterface,TImplementation>.Create(fResolver),aName).AsSingleton;
  353. end;
  354. function TIocContainer.Resolve(aServiceType: PTypeInfo; const aName: string): TValue;
  355. begin
  356. Result := fResolver.Resolve(aServiceType,aName);
  357. end;
  358. function TIocContainer.Resolve<T>(const aName : string = ''): T;
  359. begin
  360. Result := fResolver.Resolve<T>(aName);
  361. end;
  362. function TIocContainer.ResolveAll<T>(const aName : string = ''): TList<T>;
  363. begin
  364. Result := fResolver.ResolveAll<T>(aName);
  365. end;
  366. { TIocRegistrator }
  367. constructor TIocRegistrator.Create;
  368. begin
  369. fDependencies := TDictionary<string,TIocRegistration>.Create;
  370. fDependencyOrder := TList<TIocRegistration>.Create;
  371. end;
  372. destructor TIocRegistrator.Destroy;
  373. var
  374. i : Integer;
  375. regs : TArray<TIocRegistration>;
  376. begin
  377. for i := fDependencyOrder.Count-1 downto 0 do
  378. begin
  379. if fDependencyOrder[i] <> nil then
  380. begin
  381. //free singleton instances not interfaced
  382. if (fDependencyOrder[i] is TIocRegistrationInstance) and
  383. (TIocRegistrationInstance(fDependencyOrder[i]).IsSingleton) then
  384. TIocRegistrationInstance(fDependencyOrder[i]).Instance.Free;
  385. fDependencyOrder[i].Free;
  386. end;
  387. end;
  388. fDependencies.Free;
  389. fDependencyOrder.Free;
  390. inherited;
  391. end;
  392. function TIocRegistrator.GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
  393. begin
  394. {$IFDEF NEXTGEN}
  395. {$IFDEF DELPHISYDNEY_UP}
  396. Result := string(aPInfo.Name);
  397. {$ELSE}
  398. Result := aPInfo .Name.ToString;
  399. {$ENDIF}
  400. {$ELSE}
  401. Result := string(aPInfo.Name);
  402. {$ENDIF}
  403. if not aName.IsEmpty then Result := Result + '.' + aName.ToLower;
  404. end;
  405. function TIocRegistrator.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
  406. var
  407. key : string;
  408. reg : TIocRegistration;
  409. begin
  410. Result := False;
  411. key := GetKey(TypeInfo(TInterface),aName);
  412. if fDependencies.TryGetValue(key,reg) then
  413. begin
  414. if reg.&Implementation = TImplementation then Result := True;
  415. end
  416. end;
  417. function TIocRegistrator.IsRegistered<T>(const aName: string): Boolean;
  418. var
  419. key : string;
  420. reg : TIocRegistration;
  421. begin
  422. Result := False;
  423. key := GetKey(TypeInfo(T),aName);
  424. if fDependencies.TryGetValue(key,reg) then
  425. begin
  426. if reg is TIocRegistrationInterface then Result := True
  427. else if (reg is TIocRegistrationInstance) {and (TIocRegistrationInterface(reg).Instance <> nil)} then Result := True;
  428. end
  429. end;
  430. function TIocRegistrator.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
  431. var
  432. reg : TIocRegistration;
  433. begin
  434. reg := RegisterInstance(TypeInfo(T),aName);
  435. Result := TIocRegistration<T>.Create(reg);
  436. end;
  437. function TIocRegistrator.RegisterInstance<TInterface>(aInstance: TInterface; const aName: string): TIocRegistration;
  438. var
  439. key : string;
  440. tpinfo : PTypeInfo;
  441. begin
  442. tpinfo := TypeInfo(TInterface);
  443. key := GetKey(tpinfo,aName);
  444. if fDependencies.TryGetValue(key,Result) then
  445. begin
  446. if Result.&Implementation = tpinfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  447. end
  448. else
  449. begin
  450. Result := TIocRegistrationInterface.Create(aName);
  451. Result.IntfInfo := tpinfo;
  452. TIocRegistrationInterface(Result).Instance := aInstance;
  453. //reg.Instance := T.Create;
  454. fDependencies.Add(key,Result);
  455. fDependencyOrder.Add(Result);
  456. end;
  457. end;
  458. function TIocRegistrator.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  459. var
  460. key : string;
  461. begin
  462. key := GetKey(aTypeInfo,aName);
  463. if fDependencies.TryGetValue(key,Result) then
  464. begin
  465. if Result.&Implementation = aTypeInfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  466. end
  467. else
  468. begin
  469. Result := TIocRegistrationInstance.Create(aName);
  470. Result.IntfInfo := aTypeInfo;
  471. Result.&Implementation := aTypeInfo.TypeData.ClassType;
  472. //reg.Instance := T.Create;
  473. fDependencies.Add(key,Result);
  474. fDependencyOrder.Add(Result);
  475. end;
  476. end;
  477. function TIocRegistrator.RegisterOptions<T>(aOptions: T): TIocRegistration<T>;
  478. var
  479. pInfo : PTypeInfo;
  480. key : string;
  481. reg : TIocRegistration;
  482. begin
  483. pInfo := TypeInfo(IOptions<T>);
  484. key := GetKey(pInfo,'');
  485. if fDependencies.TryGetValue(key,reg) then
  486. begin
  487. if reg.&Implementation = aOptions.ClassType then raise EIocRegisterError.Create('Implementation for this interface is already registered!');
  488. end
  489. else
  490. begin
  491. reg := TIocRegistrationInterface.Create('');
  492. reg.IntfInfo := pInfo;
  493. reg.&Implementation := aOptions.ClassType;
  494. TIocRegistrationInterface(reg).Instance := TOptionValue<T>.Create(aOptions);
  495. fDependencies.Add(key,reg);
  496. fDependencyOrder.Add(reg);
  497. end;
  498. Result := TIocRegistration<T>.Create(reg);
  499. end;
  500. function TIocRegistrator.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
  501. var
  502. reg : TIocRegistration;
  503. begin
  504. reg := RegisterType(TypeInfo(TInterface),TImplementation,aName);
  505. Result := TIocRegistration<TImplementation>.Create(reg);
  506. end;
  507. function TIocRegistrator.RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
  508. var
  509. key : string;
  510. begin
  511. key := GetKey(aTypeInfo,aName);
  512. if fDependencies.TryGetValue(key,Result) then
  513. begin
  514. if Result.&Implementation = aImplementation then raise EIocRegisterError.Create('Implementation for this interface is already registered!')
  515. else Key := key + '#' + TGUID.NewGuid.ToString;
  516. end;
  517. Result := TIocRegistrationInterface.Create(aName);
  518. Result.IntfInfo := aTypeInfo;
  519. Result.&Implementation := aImplementation;
  520. fDependencies.Add(key,Result);
  521. fDependencyOrder.Add(Result);
  522. end;
  523. { TIocResolver }
  524. constructor TIocResolver.Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
  525. begin
  526. fRegistrator := aRegistrator;
  527. fInjector := aInjector;
  528. end;
  529. function TIocResolver.CreateInstance(aClass: TClass): TValue;
  530. var
  531. ctx : TRttiContext;
  532. rtype : TRttiType;
  533. rmethod : TRttiMethod;
  534. rParam : TRttiParameter;
  535. value : TValue;
  536. values : TArray<TValue>;
  537. att: TCustomAttribute;
  538. attname: string;
  539. begin
  540. Result := nil;
  541. rtype := ctx.GetType(aClass);
  542. if rtype = nil then Exit;
  543. for rmethod in TRttiInstanceType(rtype).GetMethods do
  544. begin
  545. if rmethod.IsConstructor then
  546. begin
  547. //if create don't have parameters
  548. if Length(rmethod.GetParameters) = 0 then
  549. begin
  550. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,[]);
  551. Break;
  552. end
  553. else
  554. begin
  555. for rParam in rmethod.GetParameters do
  556. begin
  557. attname := EmptyStr;
  558. for att in rParam.GetAttributes do
  559. begin
  560. if att is Name then
  561. begin
  562. attname := Name(att).Name;
  563. Break;
  564. end;
  565. end;
  566. value := Resolve(rParam.ParamType.Handle, attname);
  567. values := values + [value];
  568. end;
  569. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,values);
  570. Break;
  571. end;
  572. end;
  573. end;
  574. end;
  575. function TIocResolver.Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
  576. var
  577. key : string;
  578. reg : TIocRegistration;
  579. intf : IInterface;
  580. begin
  581. Result := nil;
  582. reg := nil;
  583. key := fRegistrator.GetKey(aServiceType,aName);
  584. {$IFDEF DEBUG_IOC}
  585. TDebugger.Trace(Self,'Resolving dependency: %s',[key]);
  586. {$ENDIF}
  587. if not fRegistrator.Dependencies.TryGetValue(key,reg) then raise EIocResolverError.CreateFmt('Type "%s" not registered for IOC!',[aServiceType.Name]);
  588. //if is singleton return already instance if exists
  589. if reg.IsSingleton then
  590. begin
  591. if reg is TIocRegistrationInterface then
  592. begin
  593. if TIocRegistrationInterface(reg).Instance <> nil then
  594. begin
  595. if TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0 then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
  596. TValue.Make(@intf,aServiceType,Result);
  597. {$IFDEF DEBUG_IOC}
  598. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  599. {$ENDIF}
  600. Exit;
  601. end;
  602. end
  603. else
  604. begin
  605. if TIocRegistrationInstance(reg).Instance <> nil then
  606. begin
  607. Result := TIocRegistrationInstance(reg).Instance;
  608. {$IFDEF DEBUG_IOC}
  609. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  610. {$ENDIF}
  611. Exit;
  612. end;
  613. end;
  614. end;
  615. //instance not created yet
  616. if reg.&Implementation = nil then raise EIocResolverError.CreateFmt('Implemention for "%s" not defined!',[aServiceType.Name]);
  617. //use activator if assigned
  618. if reg is TIocRegistrationInterface then
  619. begin
  620. {$IFDEF DEBUG_IOC}
  621. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  622. {$ENDIF}
  623. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInterface(reg).Instance := reg.ActivatorDelegate().AsInterface
  624. else TIocRegistrationInterface(reg).Instance := CreateInstance(reg.&Implementation).AsInterface;
  625. if (TIocRegistrationInterface(reg).Instance = nil) or (TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0) then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
  626. TValue.Make(@intf,aServiceType,Result);
  627. end
  628. else
  629. begin
  630. {$IFDEF DEBUG_IOC}
  631. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  632. {$ENDIF}
  633. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInstance(reg).Instance := reg.ActivatorDelegate().AsObject
  634. else
  635. begin
  636. TIocRegistrationInstance(reg).Instance := CreateInstance(reg.&Implementation).AsObject;
  637. end;
  638. Result := TIocRegistrationInstance(reg).Instance;
  639. end;
  640. {$IFDEF DEBUG_IOC}
  641. TDebugger.Trace(Self,'Built dependency: %s',[reg.fIntfInfo.Name]);
  642. {$ENDIF}
  643. end;
  644. function TIocResolver.Resolve<T>(const aName : string = ''): T;
  645. var
  646. pInfo : PTypeInfo;
  647. begin
  648. Result := Default(T);
  649. pInfo := TypeInfo(T);
  650. Result := Resolve(pInfo,aName).AsType<T>;
  651. end;
  652. function TIocResolver.ResolveAll<T>(const aName : string = '') : TList<T>;
  653. var
  654. pInfo : PTypeInfo;
  655. reg : TIocRegistration;
  656. begin
  657. Result := TList<T>.Create;
  658. pInfo := TypeInfo(T);
  659. for reg in fRegistrator.fDependencyOrder do
  660. begin
  661. if reg.IntfInfo = pInfo then Self.Resolve(pInfo,aName);
  662. end;
  663. end;
  664. { TIocRegistration<T> }
  665. function TIocRegistration<T>.AsScoped: TIocRegistration<T>;
  666. begin
  667. Result := Self;
  668. fRegistration.AsScoped;
  669. end;
  670. function TIocRegistration<T>.AsSingleton: TIocRegistration<T>;
  671. begin
  672. Result := Self;
  673. fRegistration.AsSingleton;
  674. end;
  675. function TIocRegistration<T>.AsTransient: TIocRegistration<T>;
  676. begin
  677. Result := Self;
  678. fRegistration.AsTransient;
  679. end;
  680. constructor TIocRegistration<T>.Create(aRegistration: TIocRegistration);
  681. begin
  682. fRegistration := aRegistration;
  683. end;
  684. function TIocRegistration<T>.DelegateTo(aDelegate: TActivatorDelegate<T>): TIocRegistration<T>;
  685. begin
  686. Result := Self;
  687. fRegistration.ActivatorDelegate := function: TValue
  688. begin
  689. Result := TValue.From<T>(aDelegate);
  690. end;
  691. end;
  692. { TTypedFactory<T> }
  693. constructor TTypedFactory<T>.Create(PIID: PTypeInfo; aResolver : TIocResolver);
  694. begin
  695. inherited Create(PIID, DoInvoke);
  696. fResolver := aResolver;
  697. end;
  698. procedure TTypedFactory<T>.DoInvoke(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
  699. begin
  700. if CompareText(Method.Name,'New') <> 0 then raise Exception.Create('TTypedFactory needs a method "New"');
  701. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  702. end;
  703. { TIocServiceLocator }
  704. class function TIocServiceLocator.GetService<T> : T;
  705. begin
  706. Result := GlobalContainer.Resolve<T>;
  707. end;
  708. class function TIocServiceLocator.TryToGetService<T>(aService : T) : Boolean;
  709. begin
  710. Result := GlobalContainer.IsRegistered<T>('');
  711. if Result then aService := GlobalContainer.Resolve<T>;
  712. end;
  713. { TSimpleFactory<T> }
  714. constructor TSimpleFactory<T>.Create(aResolver: TIocResolver);
  715. begin
  716. fResolver := aResolver;
  717. end;
  718. function TSimpleFactory<T>.New: T;
  719. begin
  720. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  721. end;
  722. { TSimpleFactory<TInterface, TImplementation> }
  723. constructor TSimpleFactory<TInterface, TImplementation>.Create(aResolver: TIocResolver);
  724. begin
  725. fResolver := aResolver;
  726. end;
  727. function TSimpleFactory<TInterface, TImplementation>.New: TInterface;
  728. begin
  729. Result := fResolver.CreateInstance(TClass(TImplementation)).AsType<TInterface>;
  730. end;
  731. { Name }
  732. constructor Name.Create(aName: string);
  733. begin
  734. fName := aName;
  735. end;
  736. end.