Quick.RTTI.Utils.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  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 : 31/03/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 GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
  39. class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
  40. class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
  41. class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
  42. class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
  43. class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
  44. {$ENDIF}
  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 = class
  67. public
  68. class function Concat<T>(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.Concat<T>(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. flat[depth] := t.GetDeclaredProperties;
  189. t := t.BaseType;
  190. end;
  191. end
  192. else
  193. begin
  194. t := aType;
  195. depth := 0;
  196. while t <> nil do
  197. begin
  198. Inc(depth);
  199. t := t.BaseType;
  200. end;
  201. SetLength(flat, depth);
  202. t := aType;
  203. depth := 0;
  204. while t <> nil do
  205. begin
  206. flat[depth] := t.GetDeclaredProperties;
  207. Inc(depth);
  208. t := t.BaseType;
  209. end;
  210. end;
  211. Result := TArrayHelper.Concat<TRttiProperty>(flat);
  212. end;
  213. class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
  214. var
  215. rtype : TRttiType;
  216. begin
  217. Result := nil;
  218. rtype := fCtx.GetType(aTypeInfo);
  219. if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
  220. end;
  221. class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
  222. var
  223. prop : TRttiProperty;
  224. proppath : string;
  225. propname : string;
  226. i : Integer;
  227. value : TValue;
  228. rtype : TRttiType;
  229. {$IFNDEF FPC}
  230. rfield : TRttiField;
  231. {$ENDIF}
  232. lastsegment : Boolean;
  233. begin
  234. Result := nil;
  235. proppath := aPropertyPath;
  236. lastsegment := False;
  237. rtype := fCtx.GetType(aInstance.ClassType);
  238. repeat
  239. i := proppath.IndexOf('.');
  240. if i > -1 then
  241. begin
  242. propname := Copy(proppath,1,i);
  243. Delete(proppath,1,i+1);
  244. end
  245. else
  246. begin
  247. propname := proppath;
  248. lastsegment := True;
  249. end;
  250. if rtype.TypeKind = TTypeKind.tkRecord then
  251. begin
  252. {$IFNDEF FPC}
  253. rfield := rtype.GetField(propname);
  254. if rfield <> nil then value := rfield.GetValue(aInstance);
  255. {$ELSE}
  256. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  257. {$ENDIF}
  258. end
  259. else
  260. begin
  261. prop := rtype.GetProperty(propname);
  262. if prop = nil then Exit;
  263. if lastsegment then Exit(prop)
  264. else value := prop.GetValue(aInstance);
  265. end;
  266. if not lastsegment then
  267. begin
  268. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  269. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  270. end;
  271. until lastsegment;
  272. Result := nil;
  273. end;
  274. {$IFNDEF FPC}
  275. class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
  276. var
  277. prop : TRttiProperty;
  278. proppath : string;
  279. propname : string;
  280. i : Integer;
  281. value : TValue;
  282. rtype : TRttiType;
  283. {$IFNDEF FPC}
  284. rfield : TRttiField;
  285. {$ENDIF}
  286. lastsegment : Boolean;
  287. begin
  288. Result := nil;
  289. proppath := aPropertyPath;
  290. lastsegment := False;
  291. rtype := fCtx.GetType(aInstance.ClassType);
  292. repeat
  293. i := proppath.IndexOf('.');
  294. if i > -1 then
  295. begin
  296. propname := Copy(proppath,1,i);
  297. Delete(proppath,1,i+1);
  298. end
  299. else
  300. begin
  301. propname := proppath;
  302. lastsegment := True;
  303. end;
  304. if rtype.TypeKind = TTypeKind.tkRecord then
  305. begin
  306. {$IFNDEF FPC}
  307. rfield := rtype.GetField(propname);
  308. if rfield <> nil then
  309. begin
  310. if lastsegment then Exit(rfield)
  311. else value := rfield.GetValue(value.GetReferenceToRawData);
  312. end;
  313. {$ELSE}
  314. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  315. {$ENDIF}
  316. end
  317. else
  318. begin
  319. prop := rtype.GetProperty(propname);
  320. if prop = nil then Exit;
  321. if lastsegment then Exit(prop)
  322. else value := prop.GetValue(aInstance);
  323. end;
  324. if not lastsegment then
  325. begin
  326. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  327. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  328. end;
  329. until lastsegment;
  330. end;
  331. {$ENDIF}
  332. class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
  333. var
  334. proppath : string;
  335. propname : string;
  336. i : Integer;
  337. value : TValue;
  338. rtype : TRttiType;
  339. rprop : TRttiProperty;
  340. {$IFNDEF FPC}
  341. rfield : TRttiField;
  342. {$ENDIF}
  343. lastsegment : Boolean;
  344. begin
  345. if not Assigned(aInstance) then Exit(False);
  346. lastsegment := False;
  347. proppath := aPropertyPath;
  348. rtype := fCtx.GetType(aInstance.ClassType);
  349. repeat
  350. Result := False;
  351. i := proppath.IndexOf('.');
  352. if i > -1 then
  353. begin
  354. propname := Copy(proppath,1,i);
  355. Delete(proppath,1,i+1);
  356. end
  357. else
  358. begin
  359. propname := proppath;
  360. lastsegment := True;
  361. end;
  362. if rtype.TypeKind = TTypeKind.tkRecord then
  363. begin
  364. {$IFNDEF FPC}
  365. rfield := rtype.GetField(propname);
  366. if rfield = nil then Exit
  367. else
  368. begin
  369. value := rfield.GetValue(value.GetReferenceToRawData);
  370. Result := True;
  371. end;
  372. {$ELSE}
  373. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  374. {$ENDIF}
  375. end
  376. else
  377. begin
  378. rprop := rtype.GetProperty(propname);
  379. if rprop = nil then Exit
  380. else
  381. begin
  382. value := rprop.GetValue(aInstance);
  383. Result := True;
  384. end;
  385. end;
  386. if not lastsegment then
  387. begin
  388. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  389. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  390. end;
  391. until lastsegment;
  392. end;
  393. class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
  394. var
  395. proppath : string;
  396. propname : string;
  397. i : Integer;
  398. value : TValue;
  399. rtype : TRttiType;
  400. rprop : TRttiProperty;
  401. {$IFNDEF FPC}
  402. rfield : TRttiField;
  403. {$ENDIF}
  404. lastsegment : Boolean;
  405. begin
  406. Result := nil;
  407. if not Assigned(aInstance) then Exit;
  408. lastsegment := False;
  409. proppath := aPropertyPath;
  410. rtype := fCtx.GetType(aInstance.ClassType);
  411. {$IFDEF FPC}
  412. value := aInstance;
  413. {$ENDIF}
  414. repeat
  415. i := proppath.IndexOf('.');
  416. if i > -1 then
  417. begin
  418. propname := Copy(proppath,1,i);
  419. Delete(proppath,1,i+1);
  420. end
  421. else
  422. begin
  423. propname := proppath;
  424. lastsegment := True;
  425. end;
  426. if rtype.TypeKind = TTypeKind.tkRecord then
  427. begin
  428. {$IFNDEF FPC}
  429. rfield := rtype.GetField(propname);
  430. if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
  431. else value := rfield.GetValue(value.GetReferenceToRawData);
  432. {$ELSE}
  433. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  434. {$ENDIF}
  435. end
  436. else
  437. begin
  438. rprop := rtype.GetProperty(propname);
  439. if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
  440. {$IFNDEF FPC}
  441. else value := rprop.GetValue(aInstance);
  442. {$ELSE}
  443. else
  444. begin
  445. if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
  446. else value := rprop.GetValue(value.AsObject);
  447. end;
  448. {$ENDIF}
  449. end;
  450. if not lastsegment then
  451. begin
  452. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  453. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  454. end;
  455. until lastsegment;
  456. Result := value;
  457. end;
  458. class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
  459. var
  460. proppath : string;
  461. propname : string;
  462. i : Integer;
  463. value : TValue;
  464. rtype : TRttiType;
  465. rprop : TRttiProperty;
  466. {$IFNDEF FPC}
  467. rfield : TRttiField;
  468. {$ENDIF}
  469. lastsegment : Boolean;
  470. begin
  471. if not Assigned(aInstance) then Exit;
  472. lastsegment := False;
  473. proppath := aPropertyPath;
  474. rtype := fCtx.GetType(aInstance.ClassType);
  475. repeat
  476. i := proppath.IndexOf('.');
  477. if i > -1 then
  478. begin
  479. propname := Copy(proppath,1,i);
  480. Delete(proppath,1,i+1);
  481. end
  482. else
  483. begin
  484. propname := proppath;
  485. lastsegment := True;
  486. end;
  487. if rtype.TypeKind = TTypeKind.tkRecord then
  488. begin
  489. {$IFNDEF FPC}
  490. rfield := rtype.GetField(propname);
  491. if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
  492. else
  493. begin
  494. if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
  495. else value := rfield.GetValue(value.GetReferenceToRawData);
  496. end;
  497. {$ELSE}
  498. raise ERTTIError.Create('FPC not supports record fields in RTTI');
  499. {$ENDIF}
  500. end
  501. else
  502. begin
  503. rprop := rtype.GetProperty(propname);
  504. if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
  505. else
  506. begin
  507. if lastsegment then rprop.SetValue(aInstance,aValue)
  508. else value := rprop.GetValue(aInstance);
  509. end;
  510. end;
  511. if not lastsegment then
  512. begin
  513. if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
  514. else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
  515. end;
  516. until lastsegment;
  517. end;
  518. class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
  519. var
  520. rprop : TRttiProperty;
  521. begin
  522. rprop := GetProperty(aInstance,aPropertyName);
  523. if rprop <> nil then
  524. begin
  525. {$IFNDEF FPC}
  526. Result := rprop.GetValue(aInstance);
  527. {$ELSE}
  528. if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
  529. else Result := rprop.GetValue(aInstance);
  530. {$ENDIF}
  531. end;
  532. end;
  533. class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
  534. var
  535. rprop : TRttiProperty;
  536. begin
  537. rprop := GetProperty(aTypeInfo,aPropertyName);
  538. if rprop <> nil then
  539. begin
  540. {$IFNDEF FPC}
  541. Result := rprop.GetValue(aTypeInfo);
  542. {$ELSE}
  543. if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
  544. else Result := rprop.GetValue(aTypeInfo);
  545. {$ENDIF}
  546. end;
  547. end;
  548. class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
  549. var
  550. pinfo : PPropInfo;
  551. begin
  552. Result := nil;
  553. pinfo := GetPropInfo(aInstance,aPropertyName);
  554. if pinfo = nil then
  555. begin
  556. //if not found can be a public property
  557. Result := GetPropertyValue(aInstance,aPropertyName);
  558. Exit;
  559. end;
  560. case pinfo.PropType^.Kind of
  561. tkInteger : Result := GetOrdProp(aInstance,pinfo);
  562. tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
  563. tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
  564. tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
  565. {$IFDEF FPC}
  566. tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
  567. tkSString,
  568. tkAString,
  569. {$ELSE}
  570. tkUString,
  571. tkWString,
  572. {$ENDIF}
  573. tkLString : Result := GetStrProp(aInstance,pinfo);
  574. {$IFDEF FPC}
  575. tkEnumeration :Result := GetOrdProp(aInstance,aPropertyName);
  576. {$ELSE}
  577. tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
  578. {$ENDIF}
  579. tkSet : Result := GetSetProp(aInstance,pinfo,True);
  580. {$IFNDEF FPC}
  581. tkClass :
  582. {$ELSE}
  583. tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
  584. tkObject :
  585. {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
  586. tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
  587. end;
  588. end;
  589. class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
  590. begin
  591. Result := fCtx.GetType(aTypeInfo);
  592. end;
  593. class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
  594. var
  595. rtype : TRttiType;
  596. begin
  597. Result := False;
  598. rtype := fCtx.GetType(aTypeInfo);
  599. if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
  600. end;
  601. class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
  602. var
  603. rprop : TRttiProperty;
  604. begin
  605. rprop := GetProperty(aInstance,aPropertyName);
  606. if rprop <> nil then rprop.SetValue(aInstance,aValue);
  607. end;
  608. {$IFNDEF FPC}
  609. class function TRTTI.FindClass(const aClassName: string): TClass;
  610. var
  611. rType : TRttiType;
  612. rList : TArray<TRttiType>;
  613. begin
  614. Result := nil;
  615. rList := fCtx.GetTypes;
  616. for rType in rList do
  617. begin
  618. if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
  619. begin
  620. Result := rType.AsInstance.MetaClassType;
  621. Break;
  622. end;
  623. end;
  624. end;
  625. {$ENDIF}
  626. end.