I think DELPHI language offers a very clear and beautiful implementation of data encapsulation via the property methods and clear getter and setter functions.
I want to access a class string list strlst via a getter and setter functions. Option #1 in the code sample works fine as expected , but option #2 calling the Stringlist.Commatext function does actually not work.
Is this a DELPHI bug or did I miss something with respect to class design?
Target : fill class stringlist without creating an external Tstringlist class, just pass commatext.
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, classes;
type
TSimpleClass = class
FStrlst: TStringList;
private
procedure SetStrList(const Value: TStringList);
public
constructor Create;
property strlst: TStringList read FStrlst write SetStrList;
end;
{ TSimpleClass }
constructor TSimpleClass.Create;
begin
inherited;
FStrlst := TStringList.Create;
end;
procedure TSimpleClass.SetStrList(const Value: TStringList);
var
i: Integer;
begin
Writeln('class getter / setter function is called ');
for i := 0 to Value.Count - 1 do
begin
FStrlst.Add(Value[i]);
end;
writeln ('content of internal strlist : ' FStrlst.CommaText )
end;
begin
var
aSimpleClass: TSimpleClass;
var
testLst: TStringList;
try
aSimpleClass := TSimpleClass.Create;
try
// option #1 is working
testLst:=TStringList.Create;
testLst.CommaText := 'a,b,c';
aSimpleClass.strlst := testLst;
// option #2 not working ... this code should also call the
// setter function
aSimpleClass.strlst.commatext := 'd,e,f';
finally
aSimpleClass.Free;
end;
writeln ('done sample code !');
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
cmd line window sample output
CodePudding user response:
Is this a DELPHI bug or did I miss something with respect to class design?
No, it is not a Delphi bug, but a misunderstanding on your part. You say "property, getter and setter function not called", and I understand you refer to getter and setter for aSimpleClass.strlst.
You have defined direct read access (of FStrLst) for TSimpleClass.strlst, thus there is no getter to be called when reading (as in // option #2), and aSimpleClass.strlst refers directly to FStrLst.
The CommaText property of TStringList has its own setter and that is called in // option #2
Edit
Or, if your intention is to not expose the TStringList at all, but only its CommaText property, that is OK as follows:
Make sure the TStringList is private, as well as a getter and setter for CommaText, and add the property CommaTxt
TSimpleClass
private
FStrlst: TStringList;
...
function GetCommaText: string;
procedure SetCommaText(s: string);
public
property CommaTxt: string read GetCommaText write SetCommaText;
...
end;
Implement the getter and setter:
function TSimpleClass.GetCommaText: string;
begin
result := FStrlst.CommaText;
end;
procedure TSimpleClass.SetCommaText(s: string);
begin
FStrLst.CommaText := s;
end;
Now you can access the CommaTxt property without exposing the TStringList.
CodePudding user response:
The reason why your option #2 doesn't fire the setter mthod is because in your option #2 you are not assigning any value to your strlst but insteadyou are interacting with the object that is being returned by the said property.
You see when you call aSimpleClass.strlst.commatext := 'd,e,f'; what happens is next:
- Getter method of the
strlstproperty is being called in order to return the reference to the TStringList object (the object thype that is defined by property) - Then the string value of
d,e,fis assigned to theComaTextproperty that belongs to the String List whose reference was returned by your property getter method.
Now if at this time the TStringList that is part of your class would still not have been created an Access Violation would have been raised since you would be trying to access property of a non existent object.
