unit formgerenc_Classes;

interface

uses orm_utils;

type
  TProspect = class(TQryRecInfo)
  private
    _ID: TNullable<Integer>;
    _Nome: TNullable<string>;
    procedure Set_Info_Integer(const Index: Integer; const Value: TNullable<Integer>);
    procedure Set_Info_String(const Index: Integer; const Value: TNullable<string>);
    
  published
    property ID: TNullable<Integer> index 0 read _ID write Set_Info_Integer;
    property Nome: TNullable<string> index 1 read _Nome write Set_Info_String;
  end;

implementation

end.

-----------------------------------

unit pixel_classes;

interface

uses
 System.SysUtils, Rtti, TypInfo;

{$TYPEINFO ON}

type
  TNullValue = record
  end;

  TNullable<T{: record}> = record
  public
    Value: T;
    HasValue: Boolean;

    class operator Implicit(const AValue: T): TNullable<T>;
    class operator Implicit(const AValue: TNullable<T>): T;
    class operator Implicit(const AValue: TNullValue): TNullable<T>;
    class operator Explicit(const AValue: T): TNullable<T>;

    // add these...
    class operator Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
    class operator NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
  end;

var NullValue: TNullValue;

{ // exemplo de uso do TNullable

  var v: TNullable<Integer>;

  v := NullValue;
  v:= 98;

  if v = NullValue then begin
    showmessage('é null');
  end;

  if v <> NullValue then begin
    showmessage('é: '+IntToStr(v));
  end;

}

implementation

class operator TNullable<T>.Implicit(const AValue: T): TNullable<T>;
begin
  Result.Value := AValue;
  Result.HasValue := True;
end;

class operator TNullable<T>.Implicit(const AValue: TNullable<T>): T;
begin
  if AValue.HasValue then
    Result := AValue.Value
  else
    Result := Default(T); // or raise an exception
end;

class operator TNullable<T>.Implicit(const AValue: TNullValue): TNullable<T>;
begin
  Result.Value := Default(T);
  Result.HasValue := False;
end;

class operator TNullable<T>.Explicit(const AValue: T): TNullable<T>;
begin
  Result.Value := AValue;
  Result.HasValue := True;
end;

class operator TNullable<T>.Equal(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
  Result := not A.HasValue;
end;

class operator TNullable<T>.NotEqual(const A: TNullable<T>; const B: TNullValue): Boolean;
begin
  Result := A.HasValue;
end;

end.

-----------------------

unit orm_utils;

interface

uses
 Classes, System.Generics.Collections, System.Generics.Defaults, System.Hash, Rtti, TypInfo, Uni, SysUtils, StrUtils, DateUtils, Data.DB, AdvCGrid, WinAPI.Windows, Vcl.Grids, Vcl.Graphics, Math, pixel_classes, interposer_class;

type
 TQryRecInfo = class
  private   
   procedure Set_Info(Index: integer; const Value: Variant);  
  public
   procedure Set_Info_String(Index: integer; const Value: string);
   procedure Set_Info_Integer(const Index: integer; const Value: Integer);      
 end;

procedure TQryRecInfo.Set_Info(Index: integer; const Value: Variant);
begin
 // to be implemented
end;

procedure TQryRecInfo.Set_Info_String(Index: integer; const Value: string);
begin
 Set_Info(index, Value);
end;

procedure TQryRecInfo.Set_Info_Integer(const Index: integer; const Value: integer);
begin
 Set_Info(index, Value);
end;

end.

----------------------
Consider the above Delphi units.

I want to use TNullable<string> instead of string and TNullable<Integer> instead of integer.
How can it be done, while keeping the Set_Info_String and Set_Info_Integer implementations in the orm_utils unit?

    Use TNullable<string> instead of string and TNullable<Integer> instead of integer.
    Keep the implementations of Set_Info_String and Set_Info_Integer in the orm_utils unit. Adapt orm_utils if needed.
    Create the Set_Info implementation. Use rtti to accomplish this.
    You may use this as a guide:
    function GetPropNameAndField(Cls: TClass; PropIndex: integer; var PropName: string; var PropKind: TTypeKind): Boolean;
var
 Ctx: TRttiContext;
 Prop: TRttiProperty;
 Attr: TCustomAttribute;
begin
 PropName:= '';
 Ctx:= TRttiContext.Create;
 for Prop in Ctx.GetType(Cls).GetProperties do
 begin
  if (Prop as TRttiInstanceProperty).Index = PropIndex then
  begin
   PropName:= Prop.Name;
   PropKind:= Prop.PropertyType.TypeKind;
   Break;
  end;
 end;
 Result:= (PropName <> '');
end;
 
    Do not override/overload the setter methods in TProspect.
    Keep the formgerenc_Classes unit as clean as possible.