Skrim 12 Posted April 5 (edited) I have never made my own classes before and I have just started to learn. There is one field FName in the class below. What if I have 50 different Fxxxxx? Do I have to write Setter and Getter for every field? Can I declare a record inside the class? Type TEmployee = class private FName : string; //FSalary : Currency; Function GetName : string; Procedure SetName(Const Value : string); public Property Name : string read GetName write SetName; end; implementation {$R *.dfm} Function TEmployee.GetName: string; begin Result:=FName; end; Procedure TEmployee.SetName(const Value: string); begin if value='' then raise Exception.Create('Name must have a value'); FName:=value; end; Edited April 5 by Skrim 1 Share this post Link to post
dummzeuch 1620 Posted April 5 (edited) If it's only about reading and writing values to the fields, there are two options: 1. Make the fields themselves public (and omit the 'F' prefix). If you later decide some of these fields should be properties, you can simply change the class without having to change the code that's using it. type TEmployee = class public Name: string; end; 2. Instead of having read and write accessor methods, declare the properties to directly access the fields: type TEmployee = class private FName: string; public property Name: string read FName write FName; end; Edited April 6 by dummzeuch Share this post Link to post
David Heffernan 2409 Posted April 5 1 hour ago, dummzeuch said: If it's only about reading and writing values to the fields, there are two options: 1. Make the fields themselves public (and omit the 'F' prefix). If you later decide some of these fields should be properties, you can simply change the class without having to change the code that's using it. type TEmployee = class public Name: string; end; 2. Instead of having read and write accessor methods, declare the properties to directly access the fields: type TEmployee = class private FName: string; public property Name: string read FName write FName; end; Where does the exception get raised? Share this post Link to post
Remy Lebeau 1567 Posted April 5 1 hour ago, David Heffernan said: Where does the exception get raised? In his example, nowhere. You would need a setter for that. Share this post Link to post
Remy Lebeau 1567 Posted April 5 (edited) 3 hours ago, Skrim said: There is one field FName in the class below. What if I have 50 different Fxxxxx? Do I have to write Setter and Getter for every field? If they all have different names/types, then yes (provided you need getters/setters at all - see dummzeuch's examples). But, if they are all related, eg Name1, Name2, etc then you can use an indexed property instead, eg: Type TEmployee = class private FNames[0..49] : string; Function GetName(Index: Integer) : string; Procedure SetName(Index: Integer; const Value : string); public Property Names[Index: Integer] : string read GetName write SetName; end; implementation {$R *.dfm} Function TEmployee.GetName(Index: Integer): string; begin Result := FNames[Index]; end; Procedure TEmployee.SetName(Index: Integer; const Value: string); begin if Value = '' then raise Exception.Create('Value must not be empty'); FNames[Index] := Value; end; Alternatively, you could do something like this: const EmployeeNameIdx := 0; EmployeeEmailIdx := 1; ... Type TEmployee = class private FValues[0..49] : string; Function GetValue(Index: Integer) : string; Procedure SetValue(Index: Integer; const Value : string); public Property Name : string read GetValue write SetValue index EmployeeNameIdx; Property Email : string read GetValue write SetValue index EmployeeEmailIdx; end; implementation {$R *.dfm} Function TEmployee.GetValue(Index: Integer): string; begin Result := FValues[Index]; end; Procedure TEmployee.SetValue(Index: Integer; const Value: string); begin if Value = '' then raise Exception.Create('Value must not be empty'); FValues[Index] := Value; end; Quote Can I declare a record inside the class? Yes, eg: Type TEmployee = class private ... public type TDetails = record ... end; ... end; Edited April 5 by Remy Lebeau 1 Share this post Link to post
dummzeuch 1620 Posted April 6 12 hours ago, David Heffernan said: Where does the exception get raised? Nowhere, as you noticed correctly. I should not try to answer any forum posts when reading on my mobile phone. I simply missed that part of the setter method. (And on the phone apparently syntax highlighting is also not possible 😞 ) One could argue though, that, if the name should not be empty, it should be initialized in the constructor and possibly not even have a setter at all. But if the property should be writable, it could be done in a setter method but still without requiring a getter method: type TEmployee = class private FName: string; public property Name: string read FName write SetName; end; procedure TEmployee.SetName(const Value: string); begin if value='' then raise Exception.Create('Name must have a value'); FName := value; end; Share this post Link to post
pmcgee 25 Posted yesterday at 11:52 AM {$APPTYPE CONSOLE} program Project1; uses System.SysUtils, System.generics.defaults; type TEmp = class FName : string; FSalary: Currency; FAcNo : integer; function Gett<T> (var field:T) : T; procedure Sett<T> (var field:T; const Value : T); end; function TEmp.Gett<T> (var field:T) : T; begin result := field; end; procedure Temp.Sett<T>(var field:T; const Value : T); begin var lComparer := TEqualityComparer<T>.Default; if lComparer.Equals(Value, Default(T)) then raise Exception.Create('Field must have a non-default value') else field := value; end; // credit to https://stackoverflow.com/questions/5344433/how-can-i-declare-a-pointer-based-on-a-generic-type // regarding Generic comparison to Default(T), and an idea of generic properties. var emp : TEmp; s : currency; a : integer; begin s := 1000.37; a := 123; emp := TEmp.Create; writeln('Name : ', emp.FName ); writeln('Salary : ', emp.FSalary:6:2 ); writeln('Ac # : ', emp.FAcNo ); writeln; emp.Sett(emp.FName, 'Abc Def'); emp.Sett(emp.FSalary, s); emp.Sett(emp.FAcNo, a); writeln('Name : ', emp.Gett(emp.FName) ); writeln('Salary : ', emp.FSalary:6:2 ); writeln('Ac # : ', emp.FAcNo ); readln; end. I was just playing around ... trying to figure out what a simple generic 'property' function could look like. Someone in 2009 had already been thinking down that track. Share this post Link to post