Quick.IOC.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. EIocRegisterError = class(Exception);
  195. EIocResolverError = class(Exception);
  196. EIocBuildError = class(Exception);
  197. //singleton global instance
  198. function GlobalContainer : TIocContainer;
  199. function ServiceLocator : TIocServiceLocator;
  200. implementation
  201. function GlobalContainer: TIocContainer;
  202. begin
  203. Result := TIocContainer.GlobalInstance;
  204. end;
  205. function ServiceLocator : TIocServiceLocator;
  206. begin
  207. Result := TIocServiceLocator.Create;
  208. end;
  209. { TIocRegistration }
  210. constructor TIocRegistration.Create;
  211. begin
  212. fRegisterMode := TRegisterMode.rmTransient;
  213. end;
  214. function TIocRegistration.AsTransient: TIocRegistration;
  215. begin
  216. Result := Self;
  217. fRegisterMode := TRegisterMode.rmTransient;
  218. end;
  219. function TIocRegistration.AsSingleton : TIocRegistration;
  220. begin
  221. Result := Self;
  222. fRegisterMode := TRegisterMode.rmSingleton;
  223. end;
  224. function TIocRegistration.AsScoped: TIocRegistration;
  225. begin
  226. Result := Self;
  227. fRegisterMode := TRegisterMode.rmScoped;
  228. end;
  229. function TIocRegistration.IsTransient: Boolean;
  230. begin
  231. Result := fRegisterMode = TRegisterMode.rmTransient;
  232. end;
  233. function TIocRegistration.IsSingleton: Boolean;
  234. begin
  235. Result := fRegisterMode = TRegisterMode.rmSingleton;
  236. end;
  237. function TIocRegistration.IsScoped: Boolean;
  238. begin
  239. Result := fRegisterMode = TRegisterMode.rmScoped;
  240. end;
  241. { TIocContainer }
  242. class constructor TIocContainer.Create;
  243. begin
  244. GlobalInstance := TIocContainer.Create;
  245. end;
  246. class destructor TIocContainer.Destroy;
  247. begin
  248. if GlobalInstance <> nil then GlobalInstance.Free;
  249. inherited;
  250. end;
  251. function TIocContainer.AbstractFactory<T>(aClass: TClass): T;
  252. begin
  253. Result := fResolver.CreateInstance(aClass).AsType<T>;
  254. end;
  255. function TIocContainer.AbstractFactory<T> : T;
  256. begin
  257. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  258. end;
  259. procedure TIocContainer.Build;
  260. var
  261. dependency : TIocRegistration;
  262. begin
  263. {$IFDEF DEBUG_IOC}
  264. TDebugger.TimeIt(Self,'Build','Container dependencies building...');
  265. {$ENDIF}
  266. for dependency in fRegistrator.DependencyOrder do
  267. begin
  268. try
  269. {$IFDEF DEBUG_IOC}
  270. TDebugger.Trace(Self,'[Building container]: %s',[dependency.fIntfInfo.Name]);
  271. {$ENDIF}
  272. if dependency.IsSingleton then fResolver.Resolve(dependency.fIntfInfo,dependency.Name);
  273. {$IFDEF DEBUG_IOC}
  274. TDebugger.Trace(Self,'[Built container]: %s',[dependency.fIntfInfo.Name]);
  275. {$ENDIF}
  276. except
  277. on E : Exception do raise EIocBuildError.CreateFmt('Build Error on "%s(%s)" dependency: %s!',[dependency.fImplementation.ClassName,dependency.Name,e.Message]);
  278. end;
  279. end;
  280. end;
  281. constructor TIocContainer.Create;
  282. begin
  283. fLogger := nil;
  284. fRegistrator := TIocRegistrator.Create;
  285. fInjector := TIocInjector.Create;
  286. fResolver := TIocResolver.Create(fRegistrator,fInjector);
  287. end;
  288. destructor TIocContainer.Destroy;
  289. begin
  290. fInjector.Free;
  291. fResolver.Free;
  292. fRegistrator.Free;
  293. fLogger := nil;
  294. inherited;
  295. end;
  296. function TIocContainer.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
  297. begin
  298. Result := fRegistrator.IsRegistered<TInterface,TImplementation>(aName);
  299. end;
  300. function TIocContainer.IsRegistered<TInterface>(const aName: string): Boolean;
  301. begin
  302. Result := fRegistrator.IsRegistered<TInterface>(aName);
  303. end;
  304. function TIocContainer.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
  305. begin
  306. Result := fRegistrator.RegisterType<TInterface, TImplementation>(aName);
  307. end;
  308. function TIocContainer.RegisterType(aInterface: PTypeInfo; aImplementation: TClass; const aName: string): TIocRegistration;
  309. begin
  310. Result := fRegistrator.RegisterType(aInterface,aImplementation,aName);
  311. end;
  312. function TIocContainer.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
  313. begin
  314. Result := fRegistrator.RegisterInstance<T>(aName);
  315. end;
  316. function TIocContainer.RegisterTypedFactory<TFactoryInterface,TFactoryType>(const aName: string): TIocRegistration<TTypedFactory<TFactoryType>>;
  317. begin
  318. Result := fRegistrator.RegisterType<TFactoryInterface,TTypedFactory<TFactoryType>>(aName).DelegateTo(function : TTypedFactory<TFactoryType>
  319. begin
  320. Result := TTypedFactory<TFactoryType>.Create(TypeInfo(TFactoryInterface),fResolver);
  321. end);
  322. end;
  323. function TIocContainer.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  324. begin
  325. Result := fRegistrator.RegisterInstance(aTypeInfo,aName);
  326. end;
  327. function TIocContainer.RegisterInstance<TInterface>(aInstance: TInterface; const aName: string): TIocRegistration;
  328. begin
  329. Result := fRegistrator.RegisterInstance<TInterface>(aInstance,aName);
  330. end;
  331. function TIocContainer.RegisterOptions<T>(aOptions: TOptions): TIocRegistration<T>;
  332. begin
  333. Result := fRegistrator.RegisterOptions<T>(aOptions).AsSingleton;
  334. end;
  335. function TIocContainer.RegisterOptions<T>(aOptions: TConfigureOptionsProc<T>): TIocRegistration<T>;
  336. var
  337. options : T;
  338. begin
  339. options := T.Create;
  340. aOptions(options);
  341. Result := Self.RegisterOptions<T>(options);
  342. end;
  343. function TIocContainer.RegisterSimpleFactory<TInterface, TImplementation>(const aName: string): TIocRegistration;
  344. begin
  345. Result := fRegistrator.RegisterInstance<IFactory<TInterface>>(TSimpleFactory<TInterface,TImplementation>.Create(fResolver),aName).AsSingleton;
  346. end;
  347. function TIocContainer.Resolve(aServiceType: PTypeInfo; const aName: string): TValue;
  348. begin
  349. Result := fResolver.Resolve(aServiceType,aName);
  350. end;
  351. function TIocContainer.Resolve<T>(const aName : string = ''): T;
  352. begin
  353. Result := fResolver.Resolve<T>(aName);
  354. end;
  355. function TIocContainer.ResolveAll<T>(const aName : string = ''): TList<T>;
  356. begin
  357. Result := fResolver.ResolveAll<T>(aName);
  358. end;
  359. { TIocRegistrator }
  360. constructor TIocRegistrator.Create;
  361. begin
  362. fDependencies := TDictionary<string,TIocRegistration>.Create;
  363. fDependencyOrder := TList<TIocRegistration>.Create;
  364. end;
  365. destructor TIocRegistrator.Destroy;
  366. var
  367. i : Integer;
  368. regs : TArray<TIocRegistration>;
  369. begin
  370. for i := fDependencyOrder.Count-1 downto 0 do
  371. begin
  372. if fDependencyOrder[i] <> nil then
  373. begin
  374. //free singleton instances not interfaced
  375. if (fDependencyOrder[i] is TIocRegistrationInstance) and (TIocRegistrationInstance(fDependencyOrder[i]).IsSingleton) then TIocRegistrationInstance(regs[i]).Instance.Free;
  376. fDependencyOrder[i].Free;
  377. end;
  378. end;
  379. fDependencies.Free;
  380. fDependencyOrder.Free;
  381. inherited;
  382. end;
  383. function TIocRegistrator.GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
  384. begin
  385. {$IFDEF NEXTGEN}
  386. {$IFDEF DELPHISYDNEY_UP}
  387. Result := string(aPInfo.Name);
  388. {$ELSE}
  389. Result := aPInfo .Name.ToString;
  390. {$ENDIF}
  391. {$ELSE}
  392. Result := string(aPInfo.Name);
  393. {$ENDIF}
  394. if not aName.IsEmpty then Result := Result + '.' + aName.ToLower;
  395. end;
  396. function TIocRegistrator.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
  397. var
  398. key : string;
  399. reg : TIocRegistration;
  400. begin
  401. Result := False;
  402. key := GetKey(TypeInfo(TInterface),aName);
  403. if fDependencies.TryGetValue(key,reg) then
  404. begin
  405. if reg.&Implementation = TImplementation then Result := True;
  406. end
  407. end;
  408. function TIocRegistrator.IsRegistered<T>(const aName: string): Boolean;
  409. var
  410. key : string;
  411. reg : TIocRegistration;
  412. begin
  413. Result := False;
  414. key := GetKey(TypeInfo(T),aName);
  415. if fDependencies.TryGetValue(key,reg) then
  416. begin
  417. if reg is TIocRegistrationInterface then Result := True
  418. else if (reg is TIocRegistrationInstance) {and (TIocRegistrationInterface(reg).Instance <> nil)} then Result := True;
  419. end
  420. end;
  421. function TIocRegistrator.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
  422. var
  423. reg : TIocRegistration;
  424. begin
  425. reg := RegisterInstance(TypeInfo(T),aName);
  426. Result := TIocRegistration<T>.Create(reg);
  427. end;
  428. function TIocRegistrator.RegisterInstance<TInterface>(aInstance: TInterface; const aName: string): TIocRegistration;
  429. var
  430. key : string;
  431. tpinfo : PTypeInfo;
  432. begin
  433. tpinfo := TypeInfo(TInterface);
  434. key := GetKey(tpinfo,aName);
  435. if fDependencies.TryGetValue(key,Result) then
  436. begin
  437. if Result.&Implementation = tpinfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  438. end
  439. else
  440. begin
  441. Result := TIocRegistrationInterface.Create(aName);
  442. Result.IntfInfo := tpinfo;
  443. TIocRegistrationInterface(Result).Instance := aInstance;
  444. //reg.Instance := T.Create;
  445. fDependencies.Add(key,Result);
  446. fDependencyOrder.Add(Result);
  447. end;
  448. end;
  449. function TIocRegistrator.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  450. var
  451. key : string;
  452. begin
  453. key := GetKey(aTypeInfo,aName);
  454. if fDependencies.TryGetValue(key,Result) then
  455. begin
  456. if Result.&Implementation = aTypeInfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  457. end
  458. else
  459. begin
  460. Result := TIocRegistrationInstance.Create(aName);
  461. Result.IntfInfo := aTypeInfo;
  462. Result.&Implementation := aTypeInfo.TypeData.ClassType;
  463. //reg.Instance := T.Create;
  464. fDependencies.Add(key,Result);
  465. fDependencyOrder.Add(Result);
  466. end;
  467. end;
  468. function TIocRegistrator.RegisterOptions<T>(aOptions: T): TIocRegistration<T>;
  469. var
  470. pInfo : PTypeInfo;
  471. key : string;
  472. reg : TIocRegistration;
  473. begin
  474. pInfo := TypeInfo(IOptions<T>);
  475. key := GetKey(pInfo,'');
  476. if fDependencies.TryGetValue(key,reg) then
  477. begin
  478. if reg.&Implementation = aOptions.ClassType then raise EIocRegisterError.Create('Implementation for this interface is already registered!');
  479. end
  480. else
  481. begin
  482. reg := TIocRegistrationInterface.Create('');
  483. reg.IntfInfo := pInfo;
  484. reg.&Implementation := aOptions.ClassType;
  485. TIocRegistrationInterface(reg).Instance := TOptionValue<T>.Create(aOptions);
  486. fDependencies.Add(key,reg);
  487. fDependencyOrder.Add(reg);
  488. end;
  489. Result := TIocRegistration<T>.Create(reg);
  490. end;
  491. function TIocRegistrator.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
  492. var
  493. reg : TIocRegistration;
  494. begin
  495. reg := RegisterType(TypeInfo(TInterface),TImplementation,aName);
  496. Result := TIocRegistration<TImplementation>.Create(reg);
  497. end;
  498. function TIocRegistrator.RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
  499. var
  500. key : string;
  501. begin
  502. key := GetKey(aTypeInfo,aName);
  503. if fDependencies.TryGetValue(key,Result) then
  504. begin
  505. if Result.&Implementation = aImplementation then raise EIocRegisterError.Create('Implementation for this interface is already registered!')
  506. else Key := key + '#' + TGUID.NewGuid.ToString;
  507. end;
  508. Result := TIocRegistrationInterface.Create(aName);
  509. Result.IntfInfo := aTypeInfo;
  510. Result.&Implementation := aImplementation;
  511. fDependencies.Add(key,Result);
  512. fDependencyOrder.Add(Result);
  513. end;
  514. { TIocResolver }
  515. constructor TIocResolver.Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
  516. begin
  517. fRegistrator := aRegistrator;
  518. fInjector := aInjector;
  519. end;
  520. function TIocResolver.CreateInstance(aClass: TClass): TValue;
  521. var
  522. ctx : TRttiContext;
  523. rtype : TRttiType;
  524. rmethod : TRttiMethod;
  525. rParam : TRttiParameter;
  526. value : TValue;
  527. values : TArray<TValue>;
  528. begin
  529. Result := nil;
  530. rtype := ctx.GetType(aClass);
  531. if rtype = nil then Exit;
  532. for rmethod in TRttiInstanceType(rtype).GetMethods do
  533. begin
  534. if rmethod.IsConstructor then
  535. begin
  536. //if create don't have parameters
  537. if Length(rmethod.GetParameters) = 0 then
  538. begin
  539. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,[]);
  540. Break;
  541. end
  542. else
  543. begin
  544. for rParam in rmethod.GetParameters do
  545. begin
  546. value := Resolve(rParam.ParamType.Handle);
  547. values := values + [value];
  548. end;
  549. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,values);
  550. Break;
  551. end;
  552. end;
  553. end;
  554. end;
  555. function TIocResolver.Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
  556. var
  557. key : string;
  558. reg : TIocRegistration;
  559. intf : IInterface;
  560. begin
  561. Result := nil;
  562. reg := nil;
  563. key := fRegistrator.GetKey(aServiceType,aName);
  564. {$IFDEF DEBUG_IOC}
  565. TDebugger.Trace(Self,'Resolving dependency: %s',[key]);
  566. {$ENDIF}
  567. if not fRegistrator.Dependencies.TryGetValue(key,reg) then raise EIocResolverError.CreateFmt('Type "%s" not registered for IOC!',[aServiceType.Name]);
  568. //if is singleton return already instance if exists
  569. if reg.IsSingleton then
  570. begin
  571. if reg is TIocRegistrationInterface then
  572. begin
  573. if TIocRegistrationInterface(reg).Instance <> nil then
  574. begin
  575. if TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0 then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
  576. TValue.Make(@intf,aServiceType,Result);
  577. {$IFDEF DEBUG_IOC}
  578. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  579. {$ENDIF}
  580. Exit;
  581. end;
  582. end
  583. else
  584. begin
  585. if TIocRegistrationInstance(reg).Instance <> nil then
  586. begin
  587. Result := TIocRegistrationInstance(reg).Instance;
  588. {$IFDEF DEBUG_IOC}
  589. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  590. {$ENDIF}
  591. Exit;
  592. end;
  593. end;
  594. end;
  595. //instance not created yet
  596. if reg.&Implementation = nil then raise EIocResolverError.CreateFmt('Implemention for "%s" not defined!',[aServiceType.Name]);
  597. //use activator if assigned
  598. if reg is TIocRegistrationInterface then
  599. begin
  600. {$IFDEF DEBUG_IOC}
  601. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  602. {$ENDIF}
  603. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInterface(reg).Instance := reg.ActivatorDelegate().AsInterface
  604. else TIocRegistrationInterface(reg).Instance := CreateInstance(reg.&Implementation).AsInterface;
  605. 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]);
  606. TValue.Make(@intf,aServiceType,Result);
  607. end
  608. else
  609. begin
  610. {$IFDEF DEBUG_IOC}
  611. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  612. {$ENDIF}
  613. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInstance(reg).Instance := reg.ActivatorDelegate().AsObject
  614. else
  615. begin
  616. TIocRegistrationInstance(reg).Instance := CreateInstance(reg.&Implementation).AsObject;
  617. end;
  618. Result := TIocRegistrationInstance(reg).Instance;
  619. end;
  620. {$IFDEF DEBUG_IOC}
  621. TDebugger.Trace(Self,'Built dependency: %s',[reg.fIntfInfo.Name]);
  622. {$ENDIF}
  623. end;
  624. function TIocResolver.Resolve<T>(const aName : string = ''): T;
  625. var
  626. pInfo : PTypeInfo;
  627. begin
  628. Result := Default(T);
  629. pInfo := TypeInfo(T);
  630. Result := Resolve(pInfo,aName).AsType<T>;
  631. end;
  632. function TIocResolver.ResolveAll<T>(const aName : string = '') : TList<T>;
  633. var
  634. pInfo : PTypeInfo;
  635. reg : TIocRegistration;
  636. begin
  637. Result := TList<T>.Create;
  638. pInfo := TypeInfo(T);
  639. for reg in fRegistrator.fDependencyOrder do
  640. begin
  641. if reg.IntfInfo = pInfo then Self.Resolve(pInfo,aName);
  642. end;
  643. end;
  644. { TIocRegistration<T> }
  645. function TIocRegistration<T>.AsScoped: TIocRegistration<T>;
  646. begin
  647. Result := Self;
  648. fRegistration.AsScoped;
  649. end;
  650. function TIocRegistration<T>.AsSingleton: TIocRegistration<T>;
  651. begin
  652. Result := Self;
  653. fRegistration.AsSingleton;
  654. end;
  655. function TIocRegistration<T>.AsTransient: TIocRegistration<T>;
  656. begin
  657. Result := Self;
  658. fRegistration.AsTransient;
  659. end;
  660. constructor TIocRegistration<T>.Create(aRegistration: TIocRegistration);
  661. begin
  662. fRegistration := aRegistration;
  663. end;
  664. function TIocRegistration<T>.DelegateTo(aDelegate: TActivatorDelegate<T>): TIocRegistration<T>;
  665. begin
  666. Result := Self;
  667. fRegistration.ActivatorDelegate := function: TValue
  668. begin
  669. Result := TValue.From<T>(aDelegate);
  670. end;
  671. end;
  672. { TTypedFactory<T> }
  673. constructor TTypedFactory<T>.Create(PIID: PTypeInfo; aResolver : TIocResolver);
  674. begin
  675. inherited Create(PIID, DoInvoke);
  676. fResolver := aResolver;
  677. end;
  678. procedure TTypedFactory<T>.DoInvoke(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
  679. begin
  680. if CompareText(Method.Name,'New') <> 0 then raise Exception.Create('TTypedFactory needs a method "New"');
  681. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  682. end;
  683. { TIocServiceLocator }
  684. class function TIocServiceLocator.GetService<T> : T;
  685. begin
  686. Result := GlobalContainer.Resolve<T>;
  687. end;
  688. class function TIocServiceLocator.TryToGetService<T>(aService : T) : Boolean;
  689. begin
  690. Result := GlobalContainer.IsRegistered<T>('');
  691. if Result then aService := GlobalContainer.Resolve<T>;
  692. end;
  693. { TSimpleFactory<T> }
  694. constructor TSimpleFactory<T>.Create(aResolver: TIocResolver);
  695. begin
  696. fResolver := aResolver;
  697. end;
  698. function TSimpleFactory<T>.New: T;
  699. begin
  700. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  701. end;
  702. { TSimpleFactory<TInterface, TImplementation> }
  703. constructor TSimpleFactory<TInterface, TImplementation>.Create(aResolver: TIocResolver);
  704. begin
  705. fResolver := aResolver;
  706. end;
  707. function TSimpleFactory<TInterface, TImplementation>.New: TInterface;
  708. begin
  709. Result := fResolver.CreateInstance(TClass(TImplementation)).AsType<TInterface>;
  710. end;
  711. end.