Quick.IOC.pas 25 KB

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