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

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
  • Thanks 2

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

×