Quick.RTTI.Utils.pas 20 KB

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