Alright, so I have a base class which we'll call TFruit
. From this there are various descendants like TApple
, TOrange
and so on. I need to save the properties of the descendant classes to a file.
In order to be able to create the right class when loading the data, each class needs to have an ID
that I write to the file before writing the actual data. Currently, I've come up with the following way of doing it:
type
TFruit = class
const ID = 0;
end;
TApple = class(TFruit)
const ID = 1;
end;
TOrange = class(TFruit)
const ID = 2;
end;
Testing this, I found out that I need to be super careful which class I declare. If I use this:
var Fruit: TFruit;
Fruit := TOrange.Create;
...then Fruit.ID
will return zero. However, declaring Fruit
as a TOrange
will yield the expected result Fruit.ID = 2
(anyone know why?)
So basically, am I doing this right or is there a better way to do it? Having to create a class function and return a value from there seems very ugly by comparison (extra function declaration, implementation and code).
An easier to maintain solution would be to create a mapping class where you register all classes you'd like to convert to an integer.
Advantages
Usage
RegisterClass.Register(0, TFruit);
RegisterClass.Register(1, TApple);
RegisterClass.Register(2, TOrange);
Implementation
TRegisterClass = class
private
FList: TStringList;
public
function FindID(AClass: TClass): Integer;
function FindClassName(const ID: Integer): string;
procedure Register(const ID: Integer; AClass: TClass);
end;
...
function TRegisterClass.FindID(AClass: TClass): Integer;
begin
Assert(Assigned(AClass));
Result := -1;
if FList.IndexOf(AClass.ClassName) <> -1 then
Result := Integer(FList.Objects[FList.IndexOf(AClass.ClassName)]);
end;
function TRegisterClass.FindClassName(const ID: Integer): string;
var
I: Integer;
begin
Result := EmptyStr;
for I := 0 to Pred(FList.Count) do
if Integer(FList.Objects[I]) = ID then
begin
Result := FList[I];
Exit;
end;
end;
procedure TRegisterClass.Register(const ID: Integer; AClass: TClass);
begin
if IsAlreadyRegistered(ID) then
raise Exception.Create('Duplicate ID Registration')
else if IsAlreadyRegistered(AClass) then
raise Exception.Create('Duplicate Class Registration');
FList.AddObject(AClass.ClassName, Pointer(ID));
end;
Please note that there are better structures to map a String to an Integer. Writing this without a compiler and don't knowing many basic structures beyond Delphi5, I've chosen an obvious implementation.
Note that the IsAlreadyRegistered overloaded functions still have to be written
there are many possibilities, for example:
function TFruit.GetClassId(): Word;
begin
Result := CRC16(ClassName);
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With