A Magical Gathering – Part 2

From Part 1:

take an enumerator, mix it with a class helper and pour it over an invokeable custom variant

There it is again. What is he just talking about?

Well, it took me a while to find that thing, as it isn’t mentioned very often. But it turned out to be exactly what I needed. So I dived into the sources and figured out what TInvokeableCustomVariant is all about and how to use it. And even the help was in this case, um,  helpful: RAD Studio Help

It turned out that you can use such variants just like classes with properties and methods. Realizing this it sprang directly to my mind: if our enumerator can return such a variant instead of that semi-usefull record index, we can access the record fields like properties:

That was the kind of code I was looking for!

As the class helper seemed to be able to cope with a little bit more, I made it responsible for returning the appropriate variant. The changes were made quickly: the enumerator’s Current property had to be a Variant and the class helper got an additional property CurrentRec also of type Variant, which is used by the enumerator’s GetCurrent method.

You need a couple of things to make your own TInvokeableVariantType descendant work. Obviously we need that descendant:

We will only have one instance of that class, so we need a record type for storing the variant data:

This is a simplified form of the TVarData record declared in system.pas and as we only have to store a reference to the dataset it can be kept as simple as possible.

At last we need a global variable holding that instance of TVarDataRecordType, a function returning the VarType of that instance and another function creating a Variant of that type.

The Clear and Copy methods of TVarDataRecordType are pretty simple and just call predefined methods from TCustomVariantType. GetProperty and SetProperty is where the work is done:

The only thing left to do is the implementation of GetCurrentRec from the class helper:

That’s it! Now we can write code like:

or

Magic, isn’t it?

You can download the complete sources from CodeCentral: 25386

About Uwe Raabe

Addicted to Pascal/Delphi since the late 70's
This entry was posted in Delphi, Programming. Bookmark the permalink.

6 Responses to A Magical Gathering – Part 2

  1. Alan Clark says:

    That’s pretty neat.

    Would it be possible to have a paramaterized enumerator that uses generics for the dataset, so you could do something like

    var
    Employee: TEmployee;
    begin
    for Employee in QuEmployee.Records do
    ShowMessage(Employee.Name);

    So you would have the benefits of type safety and class completion? The enumerator could use attributes to figure out how to extract the fields into the Temployee class/record.

    • Uwe Raabe says:

      Interesting idea! Will have a look at it. After all the code is over two years old so it is time for an update.

  2. Alan Clark says:

    My comment was supposed be QuEmployee.Records(TEmployee) with greater and less than signs instead of brackets but they got strippd out.

  3. Cobus Kruger says:

    I saw this back when you first showed it on CC and have been using it since. Great work!

  4. Alan Clark says:

    I investigated adding generic support as I mentioned above, the only problem is that class helpers can’t be parameterized so the enumerator would have to be explicitly created.

    Other than that it’s quite simple, just use an attribute to define the database field mapping for the class fields. The enumerator would use RTTI to find this attribute in the class and extract the value from the dataset, and return an instance of the class for each record.

Comments are closed.