Quick.IOC.pas 24 KB

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