Quick.IOC.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  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
  376. (TIocRegistrationInstance(fDependencyOrder[i]).IsSingleton) then
  377. TIocRegistrationInstance(fDependencyOrder[i]).Instance.Free;
  378. fDependencyOrder[i].Free;
  379. end;
  380. end;
  381. fDependencies.Free;
  382. fDependencyOrder.Free;
  383. inherited;
  384. end;
  385. function TIocRegistrator.GetKey(aPInfo : PTypeInfo; const aName : string = ''): string;
  386. begin
  387. {$IFDEF NEXTGEN}
  388. {$IFDEF DELPHISYDNEY_UP}
  389. Result := string(aPInfo.Name);
  390. {$ELSE}
  391. Result := aPInfo .Name.ToString;
  392. {$ENDIF}
  393. {$ELSE}
  394. Result := string(aPInfo.Name);
  395. {$ENDIF}
  396. if not aName.IsEmpty then Result := Result + '.' + aName.ToLower;
  397. end;
  398. function TIocRegistrator.IsRegistered<TInterface, TImplementation>(const aName: string): Boolean;
  399. var
  400. key : string;
  401. reg : TIocRegistration;
  402. begin
  403. Result := False;
  404. key := GetKey(TypeInfo(TInterface),aName);
  405. if fDependencies.TryGetValue(key,reg) then
  406. begin
  407. if reg.&Implementation = TImplementation then Result := True;
  408. end
  409. end;
  410. function TIocRegistrator.IsRegistered<T>(const aName: string): Boolean;
  411. var
  412. key : string;
  413. reg : TIocRegistration;
  414. begin
  415. Result := False;
  416. key := GetKey(TypeInfo(T),aName);
  417. if fDependencies.TryGetValue(key,reg) then
  418. begin
  419. if reg is TIocRegistrationInterface then Result := True
  420. else if (reg is TIocRegistrationInstance) {and (TIocRegistrationInterface(reg).Instance <> nil)} then Result := True;
  421. end
  422. end;
  423. function TIocRegistrator.RegisterInstance<T>(const aName: string): TIocRegistration<T>;
  424. var
  425. reg : TIocRegistration;
  426. begin
  427. reg := RegisterInstance(TypeInfo(T),aName);
  428. Result := TIocRegistration<T>.Create(reg);
  429. end;
  430. function TIocRegistrator.RegisterInstance<TInterface>(aInstance: TInterface; const aName: string): TIocRegistration;
  431. var
  432. key : string;
  433. tpinfo : PTypeInfo;
  434. begin
  435. tpinfo := TypeInfo(TInterface);
  436. key := GetKey(tpinfo,aName);
  437. if fDependencies.TryGetValue(key,Result) then
  438. begin
  439. if Result.&Implementation = tpinfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  440. end
  441. else
  442. begin
  443. Result := TIocRegistrationInterface.Create(aName);
  444. Result.IntfInfo := tpinfo;
  445. TIocRegistrationInterface(Result).Instance := aInstance;
  446. //reg.Instance := T.Create;
  447. fDependencies.Add(key,Result);
  448. fDependencyOrder.Add(Result);
  449. end;
  450. end;
  451. function TIocRegistrator.RegisterInstance(aTypeInfo : PTypeInfo; const aName : string = '') : TIocRegistration;
  452. var
  453. key : string;
  454. begin
  455. key := GetKey(aTypeInfo,aName);
  456. if fDependencies.TryGetValue(key,Result) then
  457. begin
  458. if Result.&Implementation = aTypeInfo.TypeData.ClassType then raise EIocRegisterError.Create('Implementation is already registered!');
  459. end
  460. else
  461. begin
  462. Result := TIocRegistrationInstance.Create(aName);
  463. Result.IntfInfo := aTypeInfo;
  464. Result.&Implementation := aTypeInfo.TypeData.ClassType;
  465. //reg.Instance := T.Create;
  466. fDependencies.Add(key,Result);
  467. fDependencyOrder.Add(Result);
  468. end;
  469. end;
  470. function TIocRegistrator.RegisterOptions<T>(aOptions: T): TIocRegistration<T>;
  471. var
  472. pInfo : PTypeInfo;
  473. key : string;
  474. reg : TIocRegistration;
  475. begin
  476. pInfo := TypeInfo(IOptions<T>);
  477. key := GetKey(pInfo,'');
  478. if fDependencies.TryGetValue(key,reg) then
  479. begin
  480. if reg.&Implementation = aOptions.ClassType then raise EIocRegisterError.Create('Implementation for this interface is already registered!');
  481. end
  482. else
  483. begin
  484. reg := TIocRegistrationInterface.Create('');
  485. reg.IntfInfo := pInfo;
  486. reg.&Implementation := aOptions.ClassType;
  487. TIocRegistrationInterface(reg).Instance := TOptionValue<T>.Create(aOptions);
  488. fDependencies.Add(key,reg);
  489. fDependencyOrder.Add(reg);
  490. end;
  491. Result := TIocRegistration<T>.Create(reg);
  492. end;
  493. function TIocRegistrator.RegisterType<TInterface, TImplementation>(const aName: string): TIocRegistration<TImplementation>;
  494. var
  495. reg : TIocRegistration;
  496. begin
  497. reg := RegisterType(TypeInfo(TInterface),TImplementation,aName);
  498. Result := TIocRegistration<TImplementation>.Create(reg);
  499. end;
  500. function TIocRegistrator.RegisterType(aTypeInfo : PTypeInfo; aImplementation : TClass; const aName : string = '') : TIocRegistration;
  501. var
  502. key : string;
  503. begin
  504. key := GetKey(aTypeInfo,aName);
  505. if fDependencies.TryGetValue(key,Result) then
  506. begin
  507. if Result.&Implementation = aImplementation then raise EIocRegisterError.Create('Implementation for this interface is already registered!')
  508. else Key := key + '#' + TGUID.NewGuid.ToString;
  509. end;
  510. Result := TIocRegistrationInterface.Create(aName);
  511. Result.IntfInfo := aTypeInfo;
  512. Result.&Implementation := aImplementation;
  513. fDependencies.Add(key,Result);
  514. fDependencyOrder.Add(Result);
  515. end;
  516. { TIocResolver }
  517. constructor TIocResolver.Create(aRegistrator : TIocRegistrator; aInjector : TIocInjector);
  518. begin
  519. fRegistrator := aRegistrator;
  520. fInjector := aInjector;
  521. end;
  522. function TIocResolver.CreateInstance(aClass: TClass): TValue;
  523. var
  524. ctx : TRttiContext;
  525. rtype : TRttiType;
  526. rmethod : TRttiMethod;
  527. rParam : TRttiParameter;
  528. value : TValue;
  529. values : TArray<TValue>;
  530. begin
  531. Result := nil;
  532. rtype := ctx.GetType(aClass);
  533. if rtype = nil then Exit;
  534. for rmethod in TRttiInstanceType(rtype).GetMethods do
  535. begin
  536. if rmethod.IsConstructor then
  537. begin
  538. //if create don't have parameters
  539. if Length(rmethod.GetParameters) = 0 then
  540. begin
  541. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,[]);
  542. Break;
  543. end
  544. else
  545. begin
  546. for rParam in rmethod.GetParameters do
  547. begin
  548. value := Resolve(rParam.ParamType.Handle);
  549. values := values + [value];
  550. end;
  551. Result := rmethod.Invoke(TRttiInstanceType(rtype).MetaclassType,values);
  552. Break;
  553. end;
  554. end;
  555. end;
  556. end;
  557. function TIocResolver.Resolve(aServiceType: PTypeInfo; const aName : string = ''): TValue;
  558. var
  559. key : string;
  560. reg : TIocRegistration;
  561. intf : IInterface;
  562. begin
  563. Result := nil;
  564. reg := nil;
  565. key := fRegistrator.GetKey(aServiceType,aName);
  566. {$IFDEF DEBUG_IOC}
  567. TDebugger.Trace(Self,'Resolving dependency: %s',[key]);
  568. {$ENDIF}
  569. if not fRegistrator.Dependencies.TryGetValue(key,reg) then raise EIocResolverError.CreateFmt('Type "%s" not registered for IOC!',[aServiceType.Name]);
  570. //if is singleton return already instance if exists
  571. if reg.IsSingleton then
  572. begin
  573. if reg is TIocRegistrationInterface then
  574. begin
  575. if TIocRegistrationInterface(reg).Instance <> nil then
  576. begin
  577. if TIocRegistrationInterface(reg).Instance.QueryInterface(GetTypeData(aServiceType).Guid,intf) <> 0 then raise EIocResolverError.CreateFmt('Implementation for "%s" not registered!',[aServiceType.Name]);
  578. TValue.Make(@intf,aServiceType,Result);
  579. {$IFDEF DEBUG_IOC}
  580. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  581. {$ENDIF}
  582. Exit;
  583. end;
  584. end
  585. else
  586. begin
  587. if TIocRegistrationInstance(reg).Instance <> nil then
  588. begin
  589. Result := TIocRegistrationInstance(reg).Instance;
  590. {$IFDEF DEBUG_IOC}
  591. TDebugger.Trace(Self,'Resolved dependency: %s',[reg.fIntfInfo.Name]);
  592. {$ENDIF}
  593. Exit;
  594. end;
  595. end;
  596. end;
  597. //instance not created yet
  598. if reg.&Implementation = nil then raise EIocResolverError.CreateFmt('Implemention for "%s" not defined!',[aServiceType.Name]);
  599. //use activator if assigned
  600. if reg is TIocRegistrationInterface then
  601. begin
  602. {$IFDEF DEBUG_IOC}
  603. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  604. {$ENDIF}
  605. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInterface(reg).Instance := reg.ActivatorDelegate().AsInterface
  606. else TIocRegistrationInterface(reg).Instance := CreateInstance(reg.&Implementation).AsInterface;
  607. 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]);
  608. TValue.Make(@intf,aServiceType,Result);
  609. end
  610. else
  611. begin
  612. {$IFDEF DEBUG_IOC}
  613. TDebugger.Trace(Self,'Building dependency: %s',[reg.fIntfInfo.Name]);
  614. {$ENDIF}
  615. if Assigned(reg.ActivatorDelegate) then TIocRegistrationInstance(reg).Instance := reg.ActivatorDelegate().AsObject
  616. else
  617. begin
  618. TIocRegistrationInstance(reg).Instance := CreateInstance(reg.&Implementation).AsObject;
  619. end;
  620. Result := TIocRegistrationInstance(reg).Instance;
  621. end;
  622. {$IFDEF DEBUG_IOC}
  623. TDebugger.Trace(Self,'Built dependency: %s',[reg.fIntfInfo.Name]);
  624. {$ENDIF}
  625. end;
  626. function TIocResolver.Resolve<T>(const aName : string = ''): T;
  627. var
  628. pInfo : PTypeInfo;
  629. begin
  630. Result := Default(T);
  631. pInfo := TypeInfo(T);
  632. Result := Resolve(pInfo,aName).AsType<T>;
  633. end;
  634. function TIocResolver.ResolveAll<T>(const aName : string = '') : TList<T>;
  635. var
  636. pInfo : PTypeInfo;
  637. reg : TIocRegistration;
  638. begin
  639. Result := TList<T>.Create;
  640. pInfo := TypeInfo(T);
  641. for reg in fRegistrator.fDependencyOrder do
  642. begin
  643. if reg.IntfInfo = pInfo then Self.Resolve(pInfo,aName);
  644. end;
  645. end;
  646. { TIocRegistration<T> }
  647. function TIocRegistration<T>.AsScoped: TIocRegistration<T>;
  648. begin
  649. Result := Self;
  650. fRegistration.AsScoped;
  651. end;
  652. function TIocRegistration<T>.AsSingleton: TIocRegistration<T>;
  653. begin
  654. Result := Self;
  655. fRegistration.AsSingleton;
  656. end;
  657. function TIocRegistration<T>.AsTransient: TIocRegistration<T>;
  658. begin
  659. Result := Self;
  660. fRegistration.AsTransient;
  661. end;
  662. constructor TIocRegistration<T>.Create(aRegistration: TIocRegistration);
  663. begin
  664. fRegistration := aRegistration;
  665. end;
  666. function TIocRegistration<T>.DelegateTo(aDelegate: TActivatorDelegate<T>): TIocRegistration<T>;
  667. begin
  668. Result := Self;
  669. fRegistration.ActivatorDelegate := function: TValue
  670. begin
  671. Result := TValue.From<T>(aDelegate);
  672. end;
  673. end;
  674. { TTypedFactory<T> }
  675. constructor TTypedFactory<T>.Create(PIID: PTypeInfo; aResolver : TIocResolver);
  676. begin
  677. inherited Create(PIID, DoInvoke);
  678. fResolver := aResolver;
  679. end;
  680. procedure TTypedFactory<T>.DoInvoke(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue);
  681. begin
  682. if CompareText(Method.Name,'New') <> 0 then raise Exception.Create('TTypedFactory needs a method "New"');
  683. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  684. end;
  685. { TIocServiceLocator }
  686. class function TIocServiceLocator.GetService<T> : T;
  687. begin
  688. Result := GlobalContainer.Resolve<T>;
  689. end;
  690. class function TIocServiceLocator.TryToGetService<T>(aService : T) : Boolean;
  691. begin
  692. Result := GlobalContainer.IsRegistered<T>('');
  693. if Result then aService := GlobalContainer.Resolve<T>;
  694. end;
  695. { TSimpleFactory<T> }
  696. constructor TSimpleFactory<T>.Create(aResolver: TIocResolver);
  697. begin
  698. fResolver := aResolver;
  699. end;
  700. function TSimpleFactory<T>.New: T;
  701. begin
  702. Result := fResolver.CreateInstance(TClass(T)).AsType<T>;
  703. end;
  704. { TSimpleFactory<TInterface, TImplementation> }
  705. constructor TSimpleFactory<TInterface, TImplementation>.Create(aResolver: TIocResolver);
  706. begin
  707. fResolver := aResolver;
  708. end;
  709. function TSimpleFactory<TInterface, TImplementation>.New: TInterface;
  710. begin
  711. Result := fResolver.CreateInstance(TClass(TImplementation)).AsType<TInterface>;
  712. end;
  713. end.