2
0

Quick.RTTI.Utils.pas 20 KB

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