Quick.RTTI.Utils.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. { ***************************************************************************
  2. Copyright (c) 2016-2020 Kike Pérez
  3. Unit : Quick.RTTI.Utils
  4. Description : Files functions
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 09/03/2018
  8. Modified : 03/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.RTTI.Utils;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. SysUtils,
  26. Quick.Commons,
  27. TypInfo,
  28. Rtti;
  29. type
  30. TRttiPropertyOrder = (roFirstBase, roFirstInherited);
  31. TRTTI = class
  32. private class var
  33. fCtx : TRttiContext;
  34. public
  35. {$IFNDEF FPC}
  36. class constructor Create;
  37. class destructor Destroy;
  38. class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
  39. class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
  40. class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
  41. class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
  42. class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
  43. {$ENDIF}
  44. class function GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
  45. class function GetType(aTypeInfo : Pointer) : TRttiType;
  46. class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
  47. class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
  48. class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
  49. {$IFNDEF FPC}
  50. class function GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
  51. {$ENDIF}
  52. class function PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
  53. class function GetPathValue(aInstance : TObject; const aPropertyPath : string) : TValue;
  54. class procedure SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
  55. class procedure SetPropertyValue(aInstance : TObject; const aPropertyName : string; aValue : TValue);
  56. class function PropertyExists(aTypeInfo : Pointer; const aPropertyName : string) : Boolean;
  57. class function GetPropertyValue(aInstance : TObject; const aPropertyName : string) : TValue; overload;
  58. class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
  59. class function GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
  60. {$IFNDEF FPC}
  61. class function FindClass(const aClassName: string): TClass;
  62. class function CreateInstance<T>: T;
  63. {$ENDIF}
  64. end;
  65. ERTTIError = class(Exception);
  66. TArrayHelper<T> = class
  67. public
  68. class function Concat(const Args: array of TArray<T>): TArray<T>; static;
  69. end;
  70. implementation
  71. { TRTTIUtils }
  72. {$IFNDEF FPC}
  73. class constructor TRTTI.Create;
  74. begin
  75. fCtx := TRttiContext.Create;
  76. end;
  77. class function TRTTI.CreateInstance<T>: T;
  78. var
  79. value: TValue;
  80. rtype: TRttiType;
  81. rmethod: TRttiMethod;
  82. rinstype: TRttiInstanceType;
  83. begin
  84. rtype := fCtx.GetType(TypeInfo(T));
  85. for rmethod in rtype.GetMethods do
  86. begin
  87. if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
  88. begin
  89. rinstype := rtype.AsInstance;
  90. value := rmethod.Invoke(rinstype.MetaclassType,[]);
  91. Result := value.AsType<T>;
  92. Exit;
  93. end;
  94. end;
  95. end;
  96. class destructor TRTTI.Destroy;
  97. begin
  98. fCtx.Free;
  99. end;
  100. class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
  101. var
  102. rtype : TRttiType;
  103. begin
  104. rtype := fCtx.GetType(aTypeInfo);
  105. Result := rtype.GetField(aFieldName) <> nil;
  106. end;
  107. class function TRTTI.GetField(aInstance: TObject; const aFieldName: string): TRttiField;
  108. var
  109. rtype : TRttiType;
  110. begin
  111. Result := nil;
  112. rtype := fCtx.GetType(aInstance.ClassInfo);
  113. if rtype <> nil then
  114. begin
  115. Result := rtype.GetField(aFieldName);
  116. end;
  117. end;
  118. class function TRTTI.GetField(aTypeInfo: Pointer; const aFieldName: string): TRttiField;
  119. var
  120. rtype : TRttiType;
  121. begin
  122. Result := nil;
  123. rtype := fCtx.GetType(aTypeInfo);
  124. if rtype <> nil then
  125. begin
  126. Result := rtype.GetField(aFieldName);
  127. end;
  128. end;
  129. class function TRTTI.GetFieldValue(aInstance : TObject; const aFieldName: string): TValue;
  130. var
  131. rfield: TRttiField;
  132. begin
  133. rfield := GetField(aInstance,aFieldName);
  134. if rfield <> nil then Result := rfield.GetValue(aInstance);
  135. end;
  136. class function TRTTI.GetFieldValue(aTypeInfo : Pointer; const aFieldName: string): TValue;
  137. var
  138. rfield: TRttiField;
  139. begin
  140. rfield := GetField(aTypeInfo,aFieldName);
  141. if rfield <> nil then rfield.GetValue(aTypeInfo);
  142. end;
  143. {$ENDIF}
  144. class function TRTTI.GetProperty(aInstance: TObject; const aPropertyName: string): TRttiProperty;
  145. var
  146. rtype : TRttiType;
  147. begin
  148. Result := nil;
  149. rtype := fCtx.GetType(aInstance.ClassInfo);
  150. if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
  151. end;
  152. class function TArrayHelper<T>.Concat(const Args: array of TArray<T>): TArray<T>;
  153. var
  154. i, j, out, len: Integer;
  155. begin
  156. len := 0;
  157. for i := 0 to High(Args) do
  158. len := len + Length(Args[i]);
  159. SetLength(Result, len);
  160. out := 0;
  161. for i := 0 to High(Args) do
  162. for j := 0 to High(Args[i]) do
  163. begin
  164. Result[out] := Args[i][j];
  165. Inc(out);
  166. end;
  167. end;
  168. class function TRTTI.GetProperties(aType: TRttiType; aOrder: TRttiPropertyOrder = roFirstBase): TArray<TRttiProperty>;
  169. var
  170. flat: TArray<TArray<TRttiProperty>>;
  171. t: TRttiType;
  172. depth: Integer;
  173. begin
  174. if aOrder = TRttiPropertyOrder.roFirstBase then
  175. begin
  176. t := aType;
  177. depth := 0;
  178. while t <> nil do
  179. begin
  180. Inc(depth);
  181. t := t.BaseType;
  182. end;
  183. SetLength(flat, depth);
  184. t := aType;
  185. while t <> nil do
  186. begin
  187. Dec(depth);
  188. {$IFNDEF FPC}
  189. flat[depth] := t.GetDeclaredProperties;
  190. {$ELSE}
  191. flat[depth] := t.GetProperties;
  192. {$ENDIF}
  193. t := t.BaseType;
  194. end;
  195. end
  196. else
  197. begin
  198. t := aType;
  199. depth := 0;
  200. while t <> nil do
  201. begin
  202. Inc(depth);
  203. t := t.BaseType;
  204. end;
  205. SetLength(flat, depth);
  206. t := aType;
  207. depth := 0;
  208. while t <> nil do
  209. begin
  210. {$IFNDEF FPC}
  211. flat[depth] := t.GetDeclaredProperties;
  212. {$ELSE}
  213. flat[depth] := t.GetProperties;
  214. {$ENDIF}
  215. Inc(depth);
  216. t := t.BaseType;
  217. end;
  218. end;
  219. Result := TArrayHelper<TRttiProperty>.Concat(flat);
  220. end;
  221. class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
  222. var
  223. rtype : TRttiType;
  224. begin
  225. Result := nil;
  226. rtype := fCtx.GetType(aTypeInfo);
  227. if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
  228. end;
  229. class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
  230. var
  231. prop : TRttiProperty;
  232. proppath : string;
  233. propname : string;
  234. i : Integer;
  235. value : TValue;
  236. rtype : TRttiType;
  237. {$IFNDEF FPC}
  238. rfield : TRttiField;
  239. {$ENDIF}
  240. lastsegment : Boolean;
  241. begin
  242. Result := nil;
  243. proppath := aPropertyPath;
  244. lastsegment := False;
  245. rtype := fCtx.GetType(aInstance.ClassType);
  246. repeat
  247. i := proppath.IndexOf('.');
  248. if i > -1 then
  249. begin
  250. propname := Copy(proppath,1,i);
  251. Delete(proppath,1,i+1);
  252. end
  253. else
  254. begin
  255. propname := proppath;
  256. lastsegment := True;
  257. end;
  258. if rtype.TypeKind = TTypeKind.tkRecord then
  259. begin
  260. {$IFNDEF FPC}
  261. rfield := rtype.GetField(propname);
  262. if rfield <> nil then value := rfield.GetValue(aInstance);
  263. {$ELSE}
  264. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  265. {$ENDIF}
  266. end
  267. else
  268. begin
  269. prop := rtype.GetProperty(propname);
  270. if prop = nil then Exit;
  271. if lastsegment then Exit(prop)
  272. else value := prop.GetValue(aInstance);
  273. end;
  274. if not lastsegment then
  275. begin
  276. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  277. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  278. end;
  279. until lastsegment;
  280. Result := nil;
  281. end;
  282. {$IFNDEF FPC}
  283. class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
  284. var
  285. prop : TRttiProperty;
  286. proppath : string;
  287. propname : string;
  288. i : Integer;
  289. value : TValue;
  290. rtype : TRttiType;
  291. {$IFNDEF FPC}
  292. rfield : TRttiField;
  293. {$ENDIF}
  294. lastsegment : Boolean;
  295. begin
  296. Result := nil;
  297. proppath := aPropertyPath;
  298. lastsegment := False;
  299. rtype := fCtx.GetType(aInstance.ClassType);
  300. repeat
  301. i := proppath.IndexOf('.');
  302. if i > -1 then
  303. begin
  304. propname := Copy(proppath,1,i);
  305. Delete(proppath,1,i+1);
  306. end
  307. else
  308. begin
  309. propname := proppath;
  310. lastsegment := True;
  311. end;
  312. if rtype.TypeKind = TTypeKind.tkRecord then
  313. begin
  314. {$IFNDEF FPC}
  315. rfield := rtype.GetField(propname);
  316. if rfield <> nil then
  317. begin
  318. if lastsegment then Exit(rfield)
  319. else value := rfield.GetValue(value.GetReferenceToRawData);
  320. end;
  321. {$ELSE}
  322. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  323. {$ENDIF}
  324. end
  325. else
  326. begin
  327. prop := rtype.GetProperty(propname);
  328. if prop = nil then Exit;
  329. if lastsegment then Exit(prop)
  330. else value := prop.GetValue(aInstance);
  331. end;
  332. if not lastsegment then
  333. begin
  334. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  335. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  336. end;
  337. until lastsegment;
  338. end;
  339. {$ENDIF}
  340. class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
  341. var
  342. proppath : string;
  343. propname : string;
  344. i : Integer;
  345. value : TValue;
  346. rtype : TRttiType;
  347. rprop : TRttiProperty;
  348. {$IFNDEF FPC}
  349. rfield : TRttiField;
  350. {$ENDIF}
  351. lastsegment : Boolean;
  352. begin
  353. if not Assigned(aInstance) then Exit(False);
  354. lastsegment := False;
  355. proppath := aPropertyPath;
  356. rtype := fCtx.GetType(aInstance.ClassType);
  357. repeat
  358. Result := False;
  359. i := proppath.IndexOf('.');
  360. if i > -1 then
  361. begin
  362. propname := Copy(proppath,1,i);
  363. Delete(proppath,1,i+1);
  364. end
  365. else
  366. begin
  367. propname := proppath;
  368. lastsegment := True;
  369. end;
  370. if rtype.TypeKind = TTypeKind.tkRecord then
  371. begin
  372. {$IFNDEF FPC}
  373. rfield := rtype.GetField(propname);
  374. if rfield = nil then Exit
  375. else
  376. begin
  377. value := rfield.GetValue(value.GetReferenceToRawData);
  378. Result := True;
  379. end;
  380. {$ELSE}
  381. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  382. {$ENDIF}
  383. end
  384. else
  385. begin
  386. rprop := rtype.GetProperty(propname);
  387. if rprop = nil then Exit
  388. else
  389. begin
  390. value := rprop.GetValue(aInstance);
  391. Result := True;
  392. end;
  393. end;
  394. if not lastsegment then
  395. begin
  396. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  397. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  398. end;
  399. until lastsegment;
  400. end;
  401. class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
  402. var
  403. proppath : string;
  404. propname : string;
  405. i : Integer;
  406. value : TValue;
  407. rtype : TRttiType;
  408. rprop : TRttiProperty;
  409. {$IFNDEF FPC}
  410. rfield : TRttiField;
  411. {$ENDIF}
  412. lastsegment : Boolean;
  413. begin
  414. Result := nil;
  415. if not Assigned(aInstance) then Exit;
  416. lastsegment := False;
  417. proppath := aPropertyPath;
  418. rtype := fCtx.GetType(aInstance.ClassType);
  419. {$IFDEF FPC}
  420. value := aInstance;
  421. {$ENDIF}
  422. repeat
  423. i := proppath.IndexOf('.');
  424. if i > -1 then
  425. begin
  426. propname := Copy(proppath,1,i);
  427. Delete(proppath,1,i+1);
  428. end
  429. else
  430. begin
  431. propname := proppath;
  432. lastsegment := True;
  433. end;
  434. if rtype.TypeKind = TTypeKind.tkRecord then
  435. begin
  436. {$IFNDEF FPC}
  437. rfield := rtype.GetField(propname);
  438. if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
  439. else value := rfield.GetValue(value.GetReferenceToRawData);
  440. {$ELSE}
  441. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  442. {$ENDIF}
  443. end
  444. else
  445. begin
  446. rprop := rtype.GetProperty(propname);
  447. if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
  448. {$IFNDEF FPC}
  449. else value := rprop.GetValue(aInstance);
  450. {$ELSE}
  451. else
  452. begin
  453. if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
  454. else value := rprop.GetValue(value.AsObject);
  455. end;
  456. {$ENDIF}
  457. end;
  458. if not lastsegment then
  459. begin
  460. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  461. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  462. end;
  463. until lastsegment;
  464. Result := value;
  465. end;
  466. class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
  467. var
  468. proppath : string;
  469. propname : string;
  470. i : Integer;
  471. value : TValue;
  472. rtype : TRttiType;
  473. rprop : TRttiProperty;
  474. {$IFNDEF FPC}
  475. rfield : TRttiField;
  476. {$ENDIF}
  477. lastsegment : Boolean;
  478. begin
  479. if not Assigned(aInstance) then Exit;
  480. lastsegment := False;
  481. proppath := aPropertyPath;
  482. rtype := fCtx.GetType(aInstance.ClassType);
  483. repeat
  484. i := proppath.IndexOf('.');
  485. if i > -1 then
  486. begin
  487. propname := Copy(proppath,1,i);
  488. Delete(proppath,1,i+1);
  489. end
  490. else
  491. begin
  492. propname := proppath;
  493. lastsegment := True;
  494. end;
  495. if rtype.TypeKind = TTypeKind.tkRecord then
  496. begin
  497. {$IFNDEF FPC}
  498. rfield := rtype.GetField(propname);
  499. if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
  500. else
  501. begin
  502. if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
  503. else value := rfield.GetValue(value.GetReferenceToRawData);
  504. end;
  505. {$ELSE}
  506. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  507. {$ENDIF}
  508. end
  509. else
  510. begin
  511. rprop := rtype.GetProperty(propname);
  512. if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
  513. else
  514. begin
  515. if lastsegment then rprop.SetValue(aInstance,aValue)
  516. else value := rprop.GetValue(aInstance);
  517. end;
  518. end;
  519. if not lastsegment then
  520. begin
  521. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  522. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  523. end;
  524. until lastsegment;
  525. end;
  526. class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
  527. var
  528. rprop : TRttiProperty;
  529. begin
  530. rprop := GetProperty(aInstance,aPropertyName);
  531. if rprop <> nil then
  532. begin
  533. {$IFNDEF FPC}
  534. Result := rprop.GetValue(aInstance);
  535. {$ELSE}
  536. if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
  537. else Result := rprop.GetValue(aInstance);
  538. {$ENDIF}
  539. end;
  540. end;
  541. class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
  542. var
  543. rprop : TRttiProperty;
  544. begin
  545. rprop := GetProperty(aTypeInfo,aPropertyName);
  546. if rprop <> nil then
  547. begin
  548. {$IFNDEF FPC}
  549. Result := rprop.GetValue(aTypeInfo);
  550. {$ELSE}
  551. if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
  552. else Result := rprop.GetValue(aTypeInfo);
  553. {$ENDIF}
  554. end;
  555. end;
  556. class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
  557. var
  558. pinfo : PPropInfo;
  559. begin
  560. Result := nil;
  561. pinfo := GetPropInfo(aInstance,aPropertyName);
  562. if pinfo = nil then
  563. begin
  564. //if not found can be a public property
  565. Result := GetPropertyValue(aInstance,aPropertyName);
  566. Exit;
  567. end;
  568. case pinfo.PropType^.Kind of
  569. tkInteger : Result := GetOrdProp(aInstance,pinfo);
  570. tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
  571. tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
  572. tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
  573. {$IFDEF FPC}
  574. tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
  575. tkSString,
  576. tkAString,
  577. {$ELSE}
  578. tkUString,
  579. tkWString,
  580. {$ENDIF}
  581. tkLString : Result := GetStrProp(aInstance,pinfo);
  582. {$IFDEF FPC}
  583. tkEnumeration :Result := GetOrdProp(aInstance,aPropertyName);
  584. {$ELSE}
  585. tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
  586. {$ENDIF}
  587. tkSet : Result := GetSetProp(aInstance,pinfo,True);
  588. {$IFNDEF FPC}
  589. tkClass :
  590. {$ELSE}
  591. tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
  592. tkObject :
  593. {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
  594. tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
  595. end;
  596. end;
  597. class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
  598. begin
  599. Result := fCtx.GetType(aTypeInfo);
  600. end;
  601. class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
  602. var
  603. rtype : TRttiType;
  604. begin
  605. Result := False;
  606. rtype := fCtx.GetType(aTypeInfo);
  607. if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
  608. end;
  609. class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
  610. var
  611. rprop : TRttiProperty;
  612. begin
  613. rprop := GetProperty(aInstance,aPropertyName);
  614. if rprop <> nil then rprop.SetValue(aInstance,aValue);
  615. end;
  616. {$IFNDEF FPC}
  617. class function TRTTI.FindClass(const aClassName: string): TClass;
  618. var
  619. rType : TRttiType;
  620. rList : TArray<TRttiType>;
  621. begin
  622. Result := nil;
  623. rList := fCtx.GetTypes;
  624. for rType in rList do
  625. begin
  626. if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
  627. begin
  628. Result := rType.AsInstance.MetaClassType;
  629. Break;
  630. end;
  631. end;
  632. end;
  633. {$ENDIF}
  634. end.