Search code examples
oopdelphidelphi-11-alexandria

Class fields not shared between descendants


Can I declare a field as static on every descendant class instead of sharing its value for all of them ?

This is the base class:

type
  TKpModelViewControllerEntity = class(TInterfacedObject, IKpEntity)
  protected
    class var ResourceName: string; 
    procedure Manage;  
  public
    class function Create: IKpEntity;
  end;

This is a descendant

unit Customers;

type
  TCustomers = class(TKpModelViewControllerEntity)
  end;

initialization
  TCustomers.ResourceName := 'customers/';

And another one:

unit Articles;

type
  TArticles = class(TKpModelViewControllerEntity)
  end;

initialization
  TArticles.ResourceName := 'articles/';

When I try to create a Customers screen (TCustomers.Create.Manage) its Resourcename has the "articles/" value instead of "customers/".

Is there a way to indicate for the static fields to hold separate values for every descendant class ?.

Thank you.


Solution

  • This can easily be achieved with attributes:

    type
      ResourceNameAttribute = class(TCustomAttribute)
      private
        FValue: string;
      public
        constructor Create(const AValue: string);
        property Value: string read FValue;
      end;
    
    type
      TKpModelViewControllerEntity = class(TInterfacedObject, IKpEntity)
      protected
        class function ResourceName: string;
        procedure Manage;
      public
        class function Create: IKpEntity;
      end;
    
    class function TKpModelViewControllerEntity.ResourceName: string;
    begin
      Result := '';
      var ctx := TRttiContext.Create;
      var cls := ctx.GetType(Self);
      var attr := cls.GetAttribute<ResourceNameAttribute>;
      if attr <> nil then
        Result := attr.Value;
    end;
    
    constructor ResourceNameAttribute.Create(const AValue: string);
    begin
      inherited Create;
      FValue := AValue;
    end;
    
    ...
    
    type
      [ResourceName('customers/')]
      TCustomers = class(TKpModelViewControllerEntity)
      end;
    
    type
      [ResourceName('articles/')]
      TArticles = class(TKpModelViewControllerEntity)
      end;