Jump to content
Nigel Thomas

record functions with parameters?

Recommended Posts

Using D12.1 CE.

 

I can do this:

 

TMyRec = record
private
  function ConvertStrAToNum: Integer;
  .
  function ConvertStrNToNum: Integer;
public
  StrA: string;
  .
  StrN: string;
  property IntA: Integer read ConvertStrAToNum;
  .
  property IntN: Integer read ConvertStrNToNum;
end;

function TMyRec.ConvertStrAToNum: Integer;
begin
  Result := StrToInt(StrA);
end;
.
function TMyRec.ConvertStrNToNum: Integer;
begin
  Result := StrToInt(StrN);
end;

 

What I'd like to be able to do:

TMyRec = record
private
  function ConvertStrToInt(const StrToConvert: string): Integer;
 public
   StrA: string;
   .
   StrN: string;
   property IntA: Integer read ConvertStrToInt(StrA);
   .
   property IntN: Integer read ConvertStrToInt(StrN);
 end;
 
function TMyRec.ConvertStrToInt(const StrToConvert: string): Integer;
begin
  Result := StrToInt(StrToConvert);
end;

But I can't.

 

Context: I'm reading strings into the record, as that is how they are read from a datafile. I could just parse the string data into integers as I read the file, but I thought the above option might be more elegant, as the conversion would only be done if later in the app I require the integer representation of the string data.

Share this post


Link to post

sorry, i can't understand your question

---

are you trying to make more than one property read from single universal function,

or you are trying to build a record for converting strings to integers ?

---

or are you trying to build a dictionary of integers based on given strings ?

this is what i can help for, if i get exactly what you want:

if a dictionary:

unit API.MyDictionary;

interface

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TDictionaryContainer = TDictionary<string, Integer>;

  TMyDictionary = class
  private
    fStrDictionary: TDictionaryContainer;
    function GetValueOrDefault(const aKey: string): Integer;
    procedure Log(const aMessage: string);
  public
    constructor Create(const aStrList: array of string);
    destructor Destroy; override;

    procedure AddOrUpdateKey(const aKey: string; aValue: Integer);
    procedure RemoveKey(const aKey: string);
    function TryGetValue(const aKey: string; out aValue: Integer): Boolean;

    property Dictionary: TDictionaryContainer read fStrDictionary;
    property Values[const aKey: string]: Integer read GetValueOrDefault;
  end;

implementation

{ TMyDictionary }

constructor TMyDictionary.Create(const aStrList: array of string);
var
  I: Integer;
begin
  fStrDictionary := TDictionaryContainer.Create;
  Log('Dictionary created.');

  for I := Low(aStrList) to High(aStrList) do
  begin
    fStrDictionary.Add(aStrList[I], 0); // Initialize all keys with a default value of 0
    Log(Format('Key "%s" added with default value 0.', [aStrList[I]]));
  end;
end;

destructor TMyDictionary.Destroy;
begin
  Log('Dictionary destroyed.');
  fStrDictionary.Free;

  inherited;
end;

procedure TMyDictionary.Log(const aMessage: string);
begin
  // Simple console output for logging.
  // Replace this with your custom logging if needed.
  Writeln('[LOG] ', aMessage);
end;

procedure TMyDictionary.AddOrUpdateKey(const aKey: string; aValue: Integer);
begin
  if fStrDictionary.ContainsKey(aKey) then
  begin
    fStrDictionary.AddOrSetValue(aKey, aValue);
    Log(Format('Key "%s" updated with value %d.', [aKey, aValue]));
  end
  else
  begin
    fStrDictionary.Add(aKey, aValue);
    Log(Format('Key "%s" added with value %d.', [aKey, aValue]));
  end;
end;

procedure TMyDictionary.RemoveKey(const aKey: string);
begin
  if not fStrDictionary.ContainsKey(aKey) then
  begin
    Log(Format('Failed to remove key "%s": Key not found.', [aKey]));
    raise Exception.CreateFmt('Key "%s" does not exist in the dictionary.', [aKey]);
  end;

  fStrDictionary.Remove(aKey);
  Log(Format('Key "%s" removed.', [aKey]));
end;

function TMyDictionary.GetValueOrDefault(const aKey: string): Integer;
begin
  if not fStrDictionary.TryGetValue(aKey, Result) then
  begin
    Result := 0; // Default value
    Log(Format('Key "%s" not found. Returning default value %d.', [aKey, Result]));
  end
  else
    Log(Format('Key "%s" found with value %d.', [aKey, Result]));
end;

function TMyDictionary.TryGetValue(const aKey: string; out aValue: Integer): Boolean;
begin
  Result := fStrDictionary.TryGetValue(aKey, aValue);
  if Result then
    Log(Format('Key "%s" found with value %d.', [aKey, aValue]))
  else
    Log(Format('Key "%s" not found.', [aKey]));
end;

end.

the dpr console test:
 

program DictionaryPrj;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  API.MyDictionary in 'API\API.MyDictionary.pas';

procedure TestMyDictionary;
var
  MyDict: TMyDictionary;
  Value: Integer;
begin
  // Create the dictionary with initial keys
  MyDict := TMyDictionary.Create(['Key1', 'Key2']);
  try
    MyDict.AddOrUpdateKey('Key1', 10);
    MyDict.AddOrUpdateKey('Key3', 15);

    MyDict.TryGetValue('Key2', Value);

    MyDict.Values['Key1'];
    MyDict.Values['Key4']; // Returns default value (0)

    MyDict.RemoveKey('Key1');
    MyDict.AddOrUpdateKey('Key1', 100);
    MyDict.Dictionary.Items['Key1'];
  finally
    MyDict.Free;
  end;
end;

begin
  try
    TestMyDictionary;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  Readln;
end.

i hope this what you looking for..

Edited by bravesofts
  • Thanks 1

Share this post


Link to post
15 hours ago, Nigel Thomas said:

What I'd like to be able to do:

...

But I can't.

This has nothing to do with records.  Properties simply don't allow you to directly pass in parameters to the getter/setter methods of the read/write specifiers.  However, there is an alternative - put the strings into an array, and then use an index specifier on the property, which will get passed to the getter method when it is called, eg:

type
  TMyRec = record
  private
    function ConvertStrToInt(IndexOfStrToConvert: Integer): Integer;
  public
    const N = ...;
  public
    StrArr: array[0..N-1] of string;
    property IntA: Integer index 0 read ConvertStrToInt;
    //...
    property IntN: Integer index N-1 read ConvertStrToInt;
  end;

function TMyRec.ConvertStrToInt(IndexOfStrToConvert: Integer): Integer;
begin
  Result := StrToInt(StrArr[IndexOfStrToConvert]);
end;

 

Edited by Remy Lebeau
  • Like 1
  • Thanks 2

Share this post


Link to post

It is now apparent to me that checking the documentation more often would be time well spent! Thanks all.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×