|
Generics with Delphi 2009 Win32
With, as a bonus, anonymous routines and routine references
Date de publication : November 13th, 2008 VIII. Generic methods VIII-A. A generic Min function VIII-B. Overloading and constraints VIII-C. Some extras for TList<T> VIII. Generic methods
We have explored so far the many possibilities offered by generics, applied to types defined by the developer. It is time
to move on to generic methods.
In many presentations of generics and templates in other languages, this use of generics is explained first. Again, I have
preferred to begin with generic types, which are used more often.
VIII-A. A generic Min function
In order to introduce the concept, we will write a class method TArrayUtils.Min<T>, which finds and returns
the smallest element of an array. We will then, of course, need a comparer of type IComparer<T>.
Like a generic type name, a generic method name must be followed by the generic parameters, between angle brackets.
Here, the generic type is the type of the elements of the array.
The implementation of the method is quite similar to classes. You have to repeat the angle brackets with the generic
types, but not their possible constraints. Our Min method will then look like this:
Nothing exceptional, as you may see ;-)
VIII-B. Overloading and constraints
Let us take advantage of this nice example to review our constraints, and provide an overloaded version for those element
types which support the IComparable<T> interface (this interface is declared in System.pas).
Before that, let us add another overload which takes a routine reference of type TComparison<T>. Remember we
can easily "convert" a TComparison<T> call-back to a IComparer<T> interface with the
TComparer<T>.Construct method.
You may observe the usage of the method CompareTo on the Left parameter. This call is of course permitted
only because of the constraint.
Now, we want to provide a fourth overloaded method, again only with the Items parameter, but with an
unconstrained T parameter. This version would use TComparer<T>.Default.
But this is impossible! Indeed, even though the constraints on types do change, the parameters (arguments) are
still the same. So, the two overloads are totally ambiguous! Therefore, the following declaration would result in a
compiler error:
Then, we must choice: abandon either the first or the second, or else use another name. And as, until base types like
Integer support the IComparable<T> interface, you will need both as often, you will have to opt for
another name ;-)
Why did I cast explicitly Default into an IComparer<T>, though it is obviously already an
IComparer<T>? Because routine references and overloads still do not work very well with each other, and the
compiler seems to get confused with the mixing. Without the cast, the compilation fails ...
VIII-C. Some extras for TList<T>
Even though the TList<T> is quite a good innovation, it could nevertheless provide some more practical
methods.
Here is, for example, an implementation of the .NET FindAll method for TList<T>. This method aims to
select a sub-list from a predicate function. What we call a predicate function is a call-back routine that takes an
element of the list, and returns True if it should be selected, False otherwise. We define a routine
reference type TPredicate<T> as follows:
Then, since it is unfortunately impossible to write a class helper for a generic class, we will write a class
method FindAll<T> which is going to to that. Since we are deprived of class helper, we will at least
take advantage of it to be more general, working with an enumerator, or an enumerable.
One can use this method as follows:
It is up to you to complement this class with other methods like FindAll :-)
Warning: include(): http:// wrapper is disabled in the server configuration by allow_url_include=0 in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generics/index.php on line 41 Warning: include(http://sjrd.developpez.com/references.inc): failed to open stream: no suitable wrapper could be found in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generics/index.php on line 41 Warning: include(): Failed opening 'http://sjrd.developpez.com/references.inc' for inclusion (include_path='.:/opt/php56/lib/php') in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generics/index.php on line 41 |
Copyright © 2008-2009 Sébastien Doeraene. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.