On 13.05.2012 12:46, Leonardo M. Ramé wrote:
On 2012-05-13 10:53:42 +0200, Sven Barth wrote:
On 13.05.2012 02:49, Leonardo M. Ramé wrote:
On 2012-05-12 13:07:18 -0300, Leonardo M. Ramé wrote:
Thanks Sven and Michalis. Using the suggestion by Michalis, I got a
solution mixing Generics and regular objects.
What I'm pursuing is to replace my TCollection based ORM, with a
Generics based one, this allow users to write less code, in a clearer
way.
The way the ORM works, is to create a TCollection instance, then execute
an ORM's method to load/save data into/from it, example:
var
lCustomers: TCustomers; // this is a TCollection descendant
begin
lCustomers := TCustomers.Create;
FConnector.LoadData(lCustomers, []);
... do something with lCustomers ...
lCustomers.Free;
end;
As you can see, FConnector.LoadData receives a TCollection as parameter,
and using RTTI, it fills each TCustomer published property.
With Michalis's solution, I can turn my ORM from TCollections to
Generics with very little changes, see how small is the unit customer
now, instead of a complete TCollection/TCollectionItem definition:
Following the same subject, inside a method receiving an TFPSList, how
can I know the type of items it will contain, even if the list is
empty?.
In a TCollection, I can use myCollection.ItemClass to know it, but in a
specialized Generic type, how can I know, in an abstract way the type of
a TFPGList<T>?. I mean, what type is T?.
You can't. That's why the method with the "parent class" might be considered
less powerful than the one with generic methods/procedures.
Regards,
Sven
Hm. Another thing I'm stuck on, is specialized classes doesn't seem to
have a ClassName, am I righ?.
Specialized classes are just normal classes. They DO have a class name,
but it is not the one that you might expect.
Following example:
=== example begin ===
type
TTest<T> = class
end;
TTest1 = specialize TTest<LongInt>;
TTest2 = specialize TTest<LongInt>;
begin
with TTest1.Create do
try
Writeln(ClassName);
finally
Free;
end;
with TTest2.Create do
try
Writeln(ClassName);
finally
Free;
end;
end.
=== example end ===
In both cases the same name "TTest$1$crc31B95292" will be written which
is composed out of the name of the generic (which is "TTest$1", where
the "$1" stands for "has one generic parameter") and the crc of the
given type parameters. This name is an implementation detail though, so
DO NOT RELY ON IT, because I WILL change it sooner or later (to be more
like "TTest<System.LongInt>").
The fact that the name is in both cases the same is because the generic
is only specialized once per unit, so that code like the following can
find the correct specialization (this works in mode Delphi):
=== example begin ===
var
t: TTest<LongInt>;
begin
t := TTest<LongInt>.Create;
try
t.Value := TTest<LongInt>.SomeConstant;
finally
t.Free;
end;
end.
=== example end ===
Regards,
Sven
--
_______________________________________________
Lazarus mailing list
[email protected]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus