Reputation: 1777
Let's say I have an object which I would like to copy.
interface
type
TPerson = Class(TObject)
public
first_name: string;
last_name: string;
address: string;
public
constructor Create;
procedure CopyTo(var s1, s2, s3: string);
...
implementation
...
procedure TPerson.CopyTo(var s1, s2, s3: string)
begin
s1 := first_name;
s2 := last_name;
s3 := address;
end;
end.
Then I can use my class like this :
...
var
name1, name2, address: string;
begin
person := TPerson.Create;
person.first_name = 'John';
person.last_name = 'Doe';
person.address = '10 Downing Street';
person.CopyTo(name1, name2, address);
end;
But if I am not interested in copying the address, I would like to be able to use it like this
...
var
name1, name2: string;
begin
person := TPerson.Create;
person.first_name = 'John';
person.last_name = 'Doe';
person.address = '10 Downing Street';
person.CopyTo(name1, name2);
// Some bad legacy code that has a lot more unstructured fields
end;
I was thinking of writing an overload CopyTo(var s1, s2: string)
or using as many buffer variables as number of string I want to forget ?
Is there a more elegant way ?
Thanks.
Upvotes: 0
Views: 358
Reputation: 43659
Let's say I have an object which I would like to copy.
Strictly speaking, that is not what you are doing here. Sure, things are being copied, but to variables, not to an object. And considering that the reference parameters, due to making use of variabels, are bothering you from specifying default values, I suggest to do your copying to an actual copy of the whole object.
Design the TPerson
class of type TPersistent
that has kind of a build-in copy mechanism (to be implemented/expanded by the designer) and extend the constructor with default parameters:
type
TPerson = Class(TPersistent)
private
FFirstName: String;
FLastName: String;
FAddress: String;
public
procedure Assign(Source: TPersistent); override;
constructor Create(AFirstName: String = ''; ALastName: String = '';
AAddress: String = ''); overload;
constructor Create(APerson: TPerson); overload;
property FirstName: String read FFirstName write FFirstName;
property LastName: String read FLastName write FLastName;
property Address: String read FAddress write FAddress;
end;
procedure TPerson.Assign(Source: TPersistent);
begin
if Source is TPerson then
begin
FFirstName := TPerson(Source).FFirstName;
FLastName := TPerson(Source).FLastName;
FAddress := TPerson(Source).FAddress;
end
else
inherited Assign(Source);
end;
constructor TPerson.Create(AFirstName, ALastName, AAddress: String);
begin
inherited Create;
FFirstName := AFirstName;
FLastName := ALastName;
FAddress := AAddress;
end;
constructor TPerson.Create(APerson: TPerson);
begin
inherited Create;
Assign(APerson);
end;
And now, your possibillities vary from:
procedure Example1;
var
Person: TPerson;
PersonCopy: TPerson;
begin
Person := TPerson.Create;
Person.FirstName := 'John';
Person.LastName := 'Doe';
Person.Address := '10 Downing Street';
PersonCopy := TPerson.Create;
PersonCopy.Assign(Person);
//...
end;
to:
procedure Example2;
var
Person: TPerson;
PersonCopy: TPerson;
begin
Person := TPerson.Create('John', 'Doe');
PersonCopy := TPerson.Create(Person);
//...
end;
Upvotes: 0
Reputation: 163287
Your question title suggests you want some kind of default parameter for the parameters you're not interested in using. Delphi doesn't support that feature. (Neither does any other language I'm aware of.) You would have to write separate functions for each combination of fields you wanted to get copies of. They can be overloads of a single name, or they can all have names indicating which fields they return; you might need separate names if the types alone don't differentiate all the combinations you wish to support.
But before you do that, take a step back and consider your goal. You've written a function that copies values from public members into variables. Why does that function need to exist at all? Just copy the members you need:
person.first_name = 'John';
person.last_name = 'Doe';
person.address = '10 Downing Street';
name1 := person.first_name;
name2 := person.last_name;
Another approach is to write a proper constructor for your class so you don't have to initialize all its fields after it's already been created. Keep copies of the values you want in advance:
name1 := 'John';
name2 := 'Doe';
person := TPerson.Create(name1, name2, '10 Downing Street');
Upvotes: 2
Reputation: 9271
In my opinion using the overloads with some more descriptive variables is the best approach. I always try to make intention revealing interfaces and names
Upvotes: 0