Quick.IOC.pas 23 KB

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