Quick.IOC.pas 25 KB

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