浏览代码

[rttiUtils] >> small bug fixed

Exilon 3 年之前
父节点
当前提交
69513b40e7
共有 1 个文件被更改,包括 677 次插入729 次删除
  1. 677 729
      Quick.RTTI.Utils.pas

+ 677 - 729
Quick.RTTI.Utils.pas

@@ -1,732 +1,680 @@
-{ ***************************************************************************
-
-  Copyright (c) 2016-2020 Kike Pérez
-
-  Unit        : Quick.RTTI.Utils
-  Description : Files functions
-  Author      : Kike Pérez
-  Version     : 1.4
-  Created     : 09/03/2018
-  Modified    : 05/11/2020
-
-  This file is part of QuickLib: https://github.com/exilon/QuickLib
-
- ***************************************************************************
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
- *************************************************************************** }
-
-unit Quick.RTTI.Utils;
-
-{$i QuickLib.inc}
-
-interface
-
-uses
-  SysUtils,
-  Quick.Commons,
-  TypInfo,
-  Rtti;
-
-type
-
-  TRttiPropertyOrder = (roFirstBase, roFirstInherited);
-
-  TRTTI = class
-  private class var
-    fCtx : TRttiContext;
-  public
-    {$IFNDEF FPC}
-    class constructor Create;
-    class destructor Destroy;
-    class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
-    class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
-    class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
-    class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
-    class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
-    {$ENDIF}
-    class function GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
-    class function GetType(aTypeInfo : Pointer) : TRttiType;
-    class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
-    class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
-    class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
-    {$IFNDEF FPC}
-    class function GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
-    {$ENDIF}
-    class function PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
-    class function GetPathValue(aInstance : TObject; const aPropertyPath : string) : TValue;
-    class procedure SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
-    class procedure SetPropertyValue(aInstance : TObject; const aPropertyName : string; aValue : TValue);
-    class function PropertyExists(aTypeInfo : Pointer; const aPropertyName : string) : Boolean;
-    class function GetPropertyValue(aInstance : TObject; const aPropertyName : string) : TValue; overload;
-    class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
-    class function GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
-    {$IFNDEF FPC}
-    class function FindClass(const aClassName: string): TClass;
-    class function CreateInstance<T>: T; overload;
-    class function CreateInstance<T>(const Args: array of TValue): T; overload;
-    class function CreateInstance(aBaseClass : TClass): TObject; overload;
-    class function CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
-    {$ENDIF}
-  end;
-
-  ERTTIError = class(Exception);
-
-  TArrayHelper<T> = class
-  public
-    class function Concat(const Args: array of TArray<T>): TArray<T>; static;
-  end;
-
-implementation
-
-{ TRTTIUtils }
-
-{$IFNDEF FPC}
-class constructor TRTTI.Create;
-begin
-  fCtx := TRttiContext.Create;
-end;
-
-class function TRTTI.CreateInstance<T>: T;
-begin
-  CreateInstance<T>([]);
-end;
-
-class function TRTTI.CreateInstance<T>(const Args: array of TValue): T;
+{ ***************************************************************************
+  Copyright (c) 2016-2020 Kike Pérez
+  Unit        : Quick.RTTI.Utils
+  Description : Files functions
+  Author      : Kike Pérez
+  Version     : 1.4
+  Created     : 09/03/2018
+  Modified    : 05/11/2020
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+ ***************************************************************************
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ *************************************************************************** }
+unit Quick.RTTI.Utils;
+{$i QuickLib.inc}
+interface
+uses
+  SysUtils,
+  Quick.Commons,
+  TypInfo,
+  Rtti;
+type
+  TRttiPropertyOrder = (roFirstBase, roFirstInherited);
+  TRTTI = class
+  private class var
+    fCtx : TRttiContext;
+  public
+    {$IFNDEF FPC}
+    class constructor Create;
+    class destructor Destroy;
+    class function GetField(aInstance : TObject; const aFieldName : string) : TRttiField; overload;
+    class function GetField(aTypeInfo : Pointer; const aFieldName : string) : TRttiField; overload;
+    class function FieldExists(aTypeInfo : Pointer; const aFieldName : string) : Boolean;
+    class function GetFieldValue(aInstance : TObject; const aFieldName : string) : TValue; overload;
+    class function GetFieldValue(aTypeInfo : Pointer; const aFieldName: string) : TValue; overload;
+    {$ENDIF}
+    class function GetProperties(aType : TRttiType; aOrder : TRttiPropertyOrder = roFirstBase) : TArray<TRttiProperty>;
+    class function GetType(aTypeInfo : Pointer) : TRttiType;
+    class function GetProperty(aInstance : TObject; const aPropertyName : string) : TRttiProperty; overload;
+    class function GetProperty(aTypeInfo : Pointer; const aPropertyName : string) : TRttiProperty; overload;
+    class function GetPropertyPath(aInstance : TObject; const aPropertyPath : string) : TRttiProperty;
+    {$IFNDEF FPC}
+    class function GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
+    {$ENDIF}
+    class function PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
+    class function GetPathValue(aInstance : TObject; const aPropertyPath : string) : TValue;
+    class procedure SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
+    class procedure SetPropertyValue(aInstance : TObject; const aPropertyName : string; aValue : TValue);
+    class function PropertyExists(aTypeInfo : Pointer; const aPropertyName : string) : Boolean;
+    class function GetPropertyValue(aInstance : TObject; const aPropertyName : string) : TValue; overload;
+    class function GetPropertyValue(aTypeInfo : Pointer; const aPropertyName : string) : TValue; overload;
+    class function GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
+    {$IFNDEF FPC}
+    class function FindClass(const aClassName: string): TClass;
+    class function CreateInstance<T>: T; overload;
+    class function CreateInstance<T>(const Args: array of TValue): T; overload;
+    class function CreateInstance(aBaseClass : TClass): TObject; overload;
+    class function CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
+    {$ENDIF}
+  end;
+  ERTTIError = class(Exception);
+  TArrayHelper<T> = class
+  public
+    class function Concat(const Args: array of TArray<T>): TArray<T>; static;
+  end;
+implementation
+{ TRTTIUtils }
+{$IFNDEF FPC}
+class constructor TRTTI.Create;
+begin
+  fCtx := TRttiContext.Create;
+end;
+class function TRTTI.CreateInstance<T>: T;
+begin
+  Result := CreateInstance<T>([]);
+end;
+class function TRTTI.CreateInstance<T>(const Args: array of TValue): T;
+var
+  value: TValue;
+  rtype: TRttiType;
+  rmethod: TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  rtype := fCtx.GetType(TypeInfo(T));
+  for rmethod in rtype.GetMethods do
+  begin
+    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = Length(Args) ) then
+    begin
+      rinstype := rtype.AsInstance;
+      value := rmethod.Invoke(rinstype.MetaclassType,Args);
+      Result := value.AsType<T>;
+      Exit;
+    end;
+  end;
+end;
+class function TRTTI.CreateInstance(aBaseClass : TClass): TObject;
+var
+  value: TValue;
+  rtype: TRttiType;
+  rmethod: TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aBaseClass);
+  for rmethod in rtype.GetMethods do
+  begin
+    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
+    begin
+      rinstype := rtype.AsInstance;
+      value := rmethod.Invoke(rinstype.MetaclassType,[]);
+      Result := value.AsType<TObject>;
+      Exit;
+    end;
+  end;
+end;
+
+class function TRTTI.CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
+var
+  rtype : TRttiType;
+  rmethod : TRttiMethod;
+  rinstype: TRttiInstanceType;
+begin
+  rtype := fCtx.GetType(aObject.ClassInfo);
+  for rmethod in rtype.GetMethods do
+  begin
+    if CompareText(rmethod.Name,aMethodName) = 0 then
+    begin
+      rinstype := rtype.AsInstance;
+      Result := rmethod.Invoke(rinstype.MetaclassType,aParams);
+    end;
+  end;
+end;
+class destructor TRTTI.Destroy;
+begin
+  fCtx.Free;
+end;
+class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
+var
+  rtype : TRttiType;
+begin
+  rtype := fCtx.GetType(aTypeInfo);
+  Result := rtype.GetField(aFieldName) <> nil;
+end;
+class function TRTTI.GetField(aInstance: TObject; const aFieldName: string): TRttiField;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aInstance.ClassInfo);
+  if rtype <> nil then
+  begin
+    Result := rtype.GetField(aFieldName);
+  end;
+end;
+class function TRTTI.GetField(aTypeInfo: Pointer; const aFieldName: string): TRttiField;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then
+  begin
+    Result := rtype.GetField(aFieldName);
+  end;
+end;
+class function TRTTI.GetFieldValue(aInstance : TObject; const aFieldName: string): TValue;
+var
+  rfield: TRttiField;
+begin
+  rfield := GetField(aInstance,aFieldName);
+  if rfield <> nil then Result := rfield.GetValue(aInstance);
+end;
+class function TRTTI.GetFieldValue(aTypeInfo : Pointer; const aFieldName: string): TValue;
+var
+  rfield: TRttiField;
+begin
+  rfield := GetField(aTypeInfo,aFieldName);
+  if rfield <> nil then rfield.GetValue(aTypeInfo);
+end;
+{$ENDIF}
+class function TRTTI.GetProperty(aInstance: TObject; const aPropertyName: string): TRttiProperty;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aInstance.ClassInfo);
+  if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
+end;
+class function TArrayHelper<T>.Concat(const Args: array of TArray<T>): TArray<T>;
+var
+  i, j, out, len: Integer;
+begin
+  len := 0;
+  for i := 0 to High(Args) do
+    len := len + Length(Args[i]);
+  SetLength(Result, len);
+  out := 0;
+  for i := 0 to High(Args) do
+    for j := 0 to High(Args[i]) do
+    begin
+      Result[out] := Args[i][j];
+      Inc(out);
+    end;
+end;
+class function TRTTI.GetProperties(aType: TRttiType; aOrder: TRttiPropertyOrder = roFirstBase): TArray<TRttiProperty>;
+var
+  flat: TArray<TArray<TRttiProperty>>;
+  t: TRttiType;
+  depth: Integer;
+begin
+  if aOrder = TRttiPropertyOrder.roFirstBase then
+  begin
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      Inc(depth);
+      t := t.BaseType;
+    end;
+    SetLength(flat, depth);
+    t := aType;
+    while t <> nil do
+    begin
+      Dec(depth);
+      {$IFNDEF FPC}
+      flat[depth] := t.GetDeclaredProperties;
+      {$ELSE}
+      flat[depth] := t.GetProperties;
+      {$ENDIF}
+      t := t.BaseType;
+    end;
+  end
+  else
+  begin
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      Inc(depth);
+      t := t.BaseType;
+    end;
+    SetLength(flat, depth);
+    t := aType;
+    depth := 0;
+    while t <> nil do
+    begin
+      {$IFNDEF FPC}
+      flat[depth] := t.GetDeclaredProperties;
+      {$ELSE}
+      flat[depth] := t.GetProperties;
+      {$ENDIF}
+      Inc(depth);
+      t := t.BaseType;
+    end;
+  end;
+  Result := TArrayHelper<TRttiProperty>.Concat(flat);
+end;
+class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
+var
+  rtype : TRttiType;
+begin
+  Result := nil;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then  Result := rtype.GetProperty(aPropertyName);
+end;
+class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
+var
+  prop : TRttiProperty;
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  proppath := aPropertyPath;
+  lastsegment := False;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield <> nil then value := rfield.GetValue(aInstance);
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      prop := rtype.GetProperty(propname);
+      if prop = nil then Exit;
+      if lastsegment then Exit(prop)
+        else value := prop.GetValue(aInstance);
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+  Result := nil;
+end;
+{$IFNDEF FPC}
+class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
+var
+  prop : TRttiProperty;
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  proppath := aPropertyPath;
+  lastsegment := False;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield <> nil then
+      begin
+        if lastsegment then Exit(rfield)
+          else value := rfield.GetValue(value.GetReferenceToRawData);
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      prop := rtype.GetProperty(propname);
+      if prop = nil then Exit;
+      if lastsegment then Exit(prop)
+        else value := prop.GetValue(aInstance);
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+{$ENDIF}
+class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  if not Assigned(aInstance) then Exit(False);
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    Result := False;
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then Exit
+      else
+      begin
+        value := rfield.GetValue(value.GetReferenceToRawData);
+        Result := True;
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then Exit
+      else
+      begin
+        value := rprop.GetValue(aInstance);
+        Result := True;
+      end;
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  Result := nil;
+  if not Assigned(aInstance) then Exit;
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  {$IFDEF FPC}
+  value := aInstance;
+  {$ENDIF}
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
+        else value := rfield.GetValue(value.GetReferenceToRawData);
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
+      {$IFNDEF FPC}
+      else value := rprop.GetValue(aInstance);
+      {$ELSE}
+      else
+      begin
+        if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
+           else value := rprop.GetValue(value.AsObject);
+      end;
+      {$ENDIF}
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+  Result := value;
+end;
+class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
+var
+  proppath : string;
+  propname : string;
+  i : Integer;
+  value : TValue;
+  rtype : TRttiType;
+  rprop : TRttiProperty;
+  {$IFNDEF FPC}
+  rfield : TRttiField;
+  {$ENDIF}
+  lastsegment : Boolean;
+begin
+  if not Assigned(aInstance) then Exit;
+  lastsegment := False;
+  proppath := aPropertyPath;
+  rtype := fCtx.GetType(aInstance.ClassType);
+  repeat
+    i := proppath.IndexOf('.');
+    if i > -1 then
+    begin
+      propname := Copy(proppath,1,i);
+      Delete(proppath,1,i+1);
+    end
+    else
+    begin
+      propname := proppath;
+      lastsegment := True;
+    end;
+    if rtype.TypeKind = TTypeKind.tkRecord then
+    begin
+      {$IFNDEF FPC}
+      rfield := rtype.GetField(propname);
+      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
+      else
+      begin
+        if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
+          else value := rfield.GetValue(value.GetReferenceToRawData);
+      end;
+      {$ELSE}
+      raise ERTTIError.Create('FPC not supports record fields in RTTI');
+      {$ENDIF}
+    end
+    else
+    begin
+      rprop := rtype.GetProperty(propname);
+      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
+      else
+      begin
+        if lastsegment then rprop.SetValue(aInstance,aValue)
+          else value := rprop.GetValue(aInstance);
+      end;
+    end;
+    if not lastsegment then
+    begin
+      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
+        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
+    end;
+  until lastsegment;
+end;
+class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aInstance,aPropertyName);
+  if rprop <> nil then
+  begin
+    {$IFNDEF FPC}
+    Result := rprop.GetValue(aInstance);
+    {$ELSE}
+    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
+      else Result := rprop.GetValue(aInstance);
+    {$ENDIF}
+  end;
+end;
+class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aTypeInfo,aPropertyName);
+  if rprop <> nil then
+  begin
+    {$IFNDEF FPC}
+    Result := rprop.GetValue(aTypeInfo);
+    {$ELSE}
+    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
+      else Result := rprop.GetValue(aTypeInfo);
+    {$ENDIF}
+  end;
+end;
+class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
+var
+  pinfo : PPropInfo;
+begin
+  Result := nil;
+  pinfo := GetPropInfo(aInstance,aPropertyName);
+  if pinfo = nil then
+  begin
+    //if not found can be a public property
+    Result := GetPropertyValue(aInstance,aPropertyName);
+    Exit;
+  end;
+  case pinfo.PropType^.Kind of
+    tkInteger : Result := GetOrdProp(aInstance,pinfo);
+    tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
+    tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
+    tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
+    {$IFDEF FPC}
+    tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
+    tkSString,
+    tkAString,
+    {$ELSE}
+    tkUString,
+    tkWString,
+    {$ENDIF}
+    tkLString : Result := GetStrProp(aInstance,pinfo);
+    {$IFDEF FPC}
+    tkEnumeration :Result  := GetOrdProp(aInstance,aPropertyName);
+    {$ELSE}
+    tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
+    {$ENDIF}
+    tkSet : Result := GetSetProp(aInstance,pinfo,True);
+    {$IFNDEF FPC}
+    tkClass :
+    {$ELSE}
+    tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
+    tkObject :
+    {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
+    tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
+  end;
+end;
+
+class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
+begin
+  Result := fCtx.GetType(aTypeInfo);
+end;
+class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
+var
+  rtype : TRttiType;
+begin
+  Result := False;
+  rtype := fCtx.GetType(aTypeInfo);
+  if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
+end;
+class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
+var
+  rprop : TRttiProperty;
+begin
+  rprop := GetProperty(aInstance,aPropertyName);
+  if rprop <> nil then rprop.SetValue(aInstance,aValue);
+end;
+{$IFNDEF FPC}
+class function TRTTI.FindClass(const aClassName: string): TClass;
 var
 var
-  value: TValue;
-  rtype: TRttiType;
-  rmethod: TRttiMethod;
-  rinstype: TRttiInstanceType;
-begin
-  rtype := fCtx.GetType(TypeInfo(T));
-  for rmethod in rtype.GetMethods do
-  begin
-
-    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = Length(Args) ) then
-    begin
-      rinstype := rtype.AsInstance;
-      value := rmethod.Invoke(rinstype.MetaclassType,Args);
-      Result := value.AsType<T>;
-      Exit;
-    end;
+  rType : TRttiType;
+  rList : TArray<TRttiType>;
+begin
+  Result := nil;
+  rList := fCtx.GetTypes;
+  for rType in rList do
+  begin
+    if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
+      begin
+        Result := rType.AsInstance.MetaClassType;
+        Break;
+      end;
   end;
   end;
-end;
-
-class function TRTTI.CreateInstance(aBaseClass : TClass): TObject;
-var
-  value: TValue;
-  rtype: TRttiType;
-  rmethod: TRttiMethod;
-  rinstype: TRttiInstanceType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aBaseClass);
-  for rmethod in rtype.GetMethods do
-  begin
-    if (rmethod.IsConstructor) and (Length(rmethod.GetParameters) = 0) then
-    begin
-      rinstype := rtype.AsInstance;
-      value := rmethod.Invoke(rinstype.MetaclassType,[]);
-      Result := value.AsType<TObject>;
-      Exit;
-    end;
-  end;
-end;
+end;
+{$ENDIF}
 
 
-class function TRTTI.CallMethod(aObject : TObject; const aMethodName : string; aParams : array of TValue) : TValue;
-var
-  rtype : TRttiType;
-  rmethod : TRttiMethod;
-  rinstype: TRttiInstanceType;
-begin
-  rtype := fCtx.GetType(aObject.ClassInfo);
-  for rmethod in rtype.GetMethods do
-  begin
-    if CompareText(rmethod.Name,aMethodName) = 0 then
-    begin
-      rinstype := rtype.AsInstance;
-      Result := rmethod.Invoke(rinstype.MetaclassType,aParams);
-    end;
-
-  end;
-end;
-
-class destructor TRTTI.Destroy;
-begin
-  fCtx.Free;
-end;
-
-class function TRTTI.FieldExists(aTypeInfo: Pointer; const aFieldName: string): Boolean;
-var
-  rtype : TRttiType;
-begin
-  rtype := fCtx.GetType(aTypeInfo);
-  Result := rtype.GetField(aFieldName) <> nil;
-end;
-
-class function TRTTI.GetField(aInstance: TObject; const aFieldName: string): TRttiField;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aInstance.ClassInfo);
-  if rtype <> nil then
-  begin
-    Result := rtype.GetField(aFieldName);
-  end;
-end;
-
-class function TRTTI.GetField(aTypeInfo: Pointer; const aFieldName: string): TRttiField;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then
-  begin
-    Result := rtype.GetField(aFieldName);
-  end;
-end;
-
-class function TRTTI.GetFieldValue(aInstance : TObject; const aFieldName: string): TValue;
-var
-  rfield: TRttiField;
-begin
-  rfield := GetField(aInstance,aFieldName);
-  if rfield <> nil then Result := rfield.GetValue(aInstance);
-end;
-
-class function TRTTI.GetFieldValue(aTypeInfo : Pointer; const aFieldName: string): TValue;
-var
-  rfield: TRttiField;
-begin
-  rfield := GetField(aTypeInfo,aFieldName);
-  if rfield <> nil then rfield.GetValue(aTypeInfo);
-end;
-{$ENDIF}
-
-class function TRTTI.GetProperty(aInstance: TObject; const aPropertyName: string): TRttiProperty;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aInstance.ClassInfo);
-  if rtype <> nil then Result := rtype.GetProperty(aPropertyName);
-end;
-
-class function TArrayHelper<T>.Concat(const Args: array of TArray<T>): TArray<T>;
-var
-  i, j, out, len: Integer;
-begin
-  len := 0;
-  for i := 0 to High(Args) do
-    len := len + Length(Args[i]);
-  SetLength(Result, len);
-  out := 0;
-  for i := 0 to High(Args) do
-    for j := 0 to High(Args[i]) do
-    begin
-      Result[out] := Args[i][j];
-      Inc(out);
-    end;
-end;
-
-class function TRTTI.GetProperties(aType: TRttiType; aOrder: TRttiPropertyOrder = roFirstBase): TArray<TRttiProperty>;
-var
-  flat: TArray<TArray<TRttiProperty>>;
-  t: TRttiType;
-  depth: Integer;
-begin
-  if aOrder = TRttiPropertyOrder.roFirstBase then
-  begin
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      Inc(depth);
-      t := t.BaseType;
-    end;
-
-    SetLength(flat, depth);
-    t := aType;
-    while t <> nil do
-    begin
-      Dec(depth);
-      {$IFNDEF FPC}
-      flat[depth] := t.GetDeclaredProperties;
-      {$ELSE}
-      flat[depth] := t.GetProperties;
-      {$ENDIF}
-      t := t.BaseType;
-    end;
-  end
-  else
-  begin
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      Inc(depth);
-      t := t.BaseType;
-    end;
-
-    SetLength(flat, depth);
-    t := aType;
-    depth := 0;
-    while t <> nil do
-    begin
-      {$IFNDEF FPC}
-      flat[depth] := t.GetDeclaredProperties;
-      {$ELSE}
-      flat[depth] := t.GetProperties;
-      {$ENDIF}
-      Inc(depth);
-      t := t.BaseType;
-    end;
-  end;
-
-  Result := TArrayHelper<TRttiProperty>.Concat(flat);
-end;
-
-class function TRTTI.GetProperty(aTypeInfo: Pointer; const aPropertyName: string): TRttiProperty;
-var
-  rtype : TRttiType;
-begin
-  Result := nil;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then  Result := rtype.GetProperty(aPropertyName);
-end;
-
-class function TRTTI.GetPropertyPath(aInstance: TObject; const aPropertyPath: string): TRttiProperty;
-var
-  prop : TRttiProperty;
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  proppath := aPropertyPath;
-  lastsegment := False;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield <> nil then value := rfield.GetValue(aInstance);
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      prop := rtype.GetProperty(propname);
-      if prop = nil then Exit;
-      if lastsegment then Exit(prop)
-        else value := prop.GetValue(aInstance);
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-  Result := nil;
-end;
-
-{$IFNDEF FPC}
-class function TRTTI.GetMemberPath(aInstance: TObject; const aPropertyPath: string): TRttiMember;
-var
-  prop : TRttiProperty;
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  proppath := aPropertyPath;
-  lastsegment := False;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield <> nil then
-      begin
-        if lastsegment then Exit(rfield)
-          else value := rfield.GetValue(value.GetReferenceToRawData);
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      prop := rtype.GetProperty(propname);
-      if prop = nil then Exit;
-      if lastsegment then Exit(prop)
-        else value := prop.GetValue(aInstance);
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-{$ENDIF}
-
-class function TRTTI.PathExists(aInstance: TObject; const aPropertyPath: string) : Boolean;
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  if not Assigned(aInstance) then Exit(False);
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    Result := False;
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then Exit
-      else
-      begin
-        value := rfield.GetValue(value.GetReferenceToRawData);
-        Result := True;
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then Exit
-      else
-      begin
-        value := rprop.GetValue(aInstance);
-        Result := True;
-      end;
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-
-class function TRTTI.GetPathValue(aInstance: TObject; const aPropertyPath: string): TValue;
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  Result := nil;
-  if not Assigned(aInstance) then Exit;
-
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  {$IFDEF FPC}
-  value := aInstance;
-  {$ENDIF}
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
-        else value := rfield.GetValue(value.GetReferenceToRawData);
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
-      {$IFNDEF FPC}
-      else value := rprop.GetValue(aInstance);
-      {$ELSE}
-      else
-      begin
-        if rprop.PropertyType.IsInstance then value := GetObjectProp(value.AsObject,propname)
-           else value := rprop.GetValue(value.AsObject);
-      end;
-      {$ENDIF}
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-  Result := value;
-end;
-
-class procedure TRTTI.SetPathValue(aInstance: TObject; const aPropertyPath: string; aValue : TValue);
-var
-  proppath : string;
-  propname : string;
-  i : Integer;
-  value : TValue;
-  rtype : TRttiType;
-  rprop : TRttiProperty;
-  {$IFNDEF FPC}
-  rfield : TRttiField;
-  {$ENDIF}
-  lastsegment : Boolean;
-begin
-  if not Assigned(aInstance) then Exit;
-  lastsegment := False;
-  proppath := aPropertyPath;
-  rtype := fCtx.GetType(aInstance.ClassType);
-  repeat
-    i := proppath.IndexOf('.');
-    if i > -1 then
-    begin
-      propname := Copy(proppath,1,i);
-      Delete(proppath,1,i+1);
-    end
-    else
-    begin
-      propname := proppath;
-      lastsegment := True;
-    end;
-    if rtype.TypeKind = TTypeKind.tkRecord then
-    begin
-      {$IFNDEF FPC}
-      rfield := rtype.GetField(propname);
-      if rfield = nil then raise ERTTIError.CreateFmt('Field "%s" not found in record',[propname])
-      else
-      begin
-        if lastsegment then rfield.SetValue(value.GetReferenceToRawData,aValue)
-          else value := rfield.GetValue(value.GetReferenceToRawData);
-      end;
-      {$ELSE}
-      raise ERTTIError.Create('FPC not supports record fields in RTTI');
-      {$ENDIF}
-    end
-    else
-    begin
-      rprop := rtype.GetProperty(propname);
-      if rprop = nil then raise ERTTIError.CreateFmt('Property "%s" not found in object',[propname])
-      else
-      begin
-        if lastsegment then rprop.SetValue(aInstance,aValue)
-          else value := rprop.GetValue(aInstance);
-      end;
-    end;
-    if not lastsegment then
-    begin
-      if value.Kind = TTypeKind.tkClass then rType := fCtx.GetType(value.AsObject.ClassType)
-        else if value.Kind = TTypeKind.tkRecord then rtype := fCtx.GetType(value.TypeInfo);
-    end;
-  until lastsegment;
-end;
-
-class function TRTTI.GetPropertyValue(aInstance: TObject; const aPropertyName: string): TValue;
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aInstance,aPropertyName);
-  if rprop <> nil then
-  begin
-    {$IFNDEF FPC}
-    Result := rprop.GetValue(aInstance);
-    {$ELSE}
-    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aInstance,aPropertyName)
-      else Result := rprop.GetValue(aInstance);
-    {$ENDIF}
-  end;
-end;
-
-class function TRTTI.GetPropertyValue(aTypeInfo: Pointer; const aPropertyName: string): TValue;
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aTypeInfo,aPropertyName);
-  if rprop <> nil then
-  begin
-    {$IFNDEF FPC}
-    Result := rprop.GetValue(aTypeInfo);
-    {$ELSE}
-    if rprop.PropertyType.IsInstance then Result := GetObjectProp(aTypeInfo,aPropertyName)
-      else Result := rprop.GetValue(aTypeInfo);
-    {$ENDIF}
-  end;
-end;
-
-class function TRTTI.GetPropertyValueEx(aInstance: TObject; const aPropertyName: string): TValue;
-var
-  pinfo : PPropInfo;
-begin
-  Result := nil;
-  pinfo := GetPropInfo(aInstance,aPropertyName);
-  if pinfo = nil then
-  begin
-    //if not found can be a public property
-    Result := GetPropertyValue(aInstance,aPropertyName);
-    Exit;
-  end;
-  case pinfo.PropType^.Kind of
-    tkInteger : Result := GetOrdProp(aInstance,pinfo);
-    tkInt64 : Result := GetInt64Prop(aInstance,aPropertyName);
-    tkFloat : Result := GetFloatProp(aInstance,aPropertyName);
-    tkChar : Result := Char(GetOrdProp(aInstance,aPropertyName));
-    {$IFDEF FPC}
-    tkWString : Result := GetWideStrProp(aInstance,aPropertyName);
-    tkSString,
-    tkAString,
-    {$ELSE}
-    tkUString,
-    tkWString,
-    {$ENDIF}
-    tkLString : Result := GetStrProp(aInstance,pinfo);
-    {$IFDEF FPC}
-    tkEnumeration :Result  := GetOrdProp(aInstance,aPropertyName);
-    {$ELSE}
-    tkEnumeration : Result := GetOrdProp(aInstance,aPropertyName);
-    {$ENDIF}
-    tkSet : Result := GetSetProp(aInstance,pinfo,True);
-    {$IFNDEF FPC}
-    tkClass :
-    {$ELSE}
-    tkBool : Result := Boolean(GetOrdProp(aInstance,pinfo));
-    tkObject :
-    {$ENDIF} Result := GetObjectProp(aInstance,pinfo);
-    tkDynArray : Result := GetDynArrayProp(aInstance,pinfo);
-  end;
-end;
-
-
-class function TRTTI.GetType(aTypeInfo: Pointer): TRttiType;
-begin
-  Result := fCtx.GetType(aTypeInfo);
-end;
-
-class function TRTTI.PropertyExists(aTypeInfo: Pointer; const aPropertyName: string) : Boolean;
-var
-  rtype : TRttiType;
-begin
-  Result := False;
-  rtype := fCtx.GetType(aTypeInfo);
-  if rtype <> nil then Result := rtype.GetProperty(aPropertyName) <> nil;
-end;
-
-class procedure TRTTI.SetPropertyValue(aInstance: TObject; const aPropertyName: string; aValue: TValue);
-var
-  rprop : TRttiProperty;
-begin
-  rprop := GetProperty(aInstance,aPropertyName);
-  if rprop <> nil then rprop.SetValue(aInstance,aValue);
-end;
-
-{$IFNDEF FPC}
-class function TRTTI.FindClass(const aClassName: string): TClass;
-var
-  rType : TRttiType;
-  rList : TArray<TRttiType>;
-begin
-  Result := nil;
-  rList := fCtx.GetTypes;
-  for rType in rList do
-  begin
-    if (rType.IsInstance) and (aClassName.EndsWith(rType.Name)) then
-      begin
-        Result := rType.AsInstance.MetaClassType;
-        Break;
-      end;
-  end;
-end;
-{$ENDIF}
-
-
-end.
+end.