IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Les génériques avec Delphi 2009 Win32

Avec en bonus les routines anonymes et les références de routine


précédentsommairesuivant

IV. Conception d'un record générique

Histoire d'aller voir d'un autre côté, développons le record simple, mais utile TNullable<T>. Son but est de valoir soit une valeur de type T, soit nil. Il est fort probable que vous ayez déjà eu besoin d'un tel type, par exemple pour représenter la valeur NULL des bases de données.

Ce record contiendra deux champs : FValue de type T et FIsNil de type Boolean, ainsi que deux propriétés permettant de lire (mais pas d'écrire) ces champs. On se servira uniquement d'opérateurs de conversion implicite pour construire des valeurs de ce type.

 
Sélectionnez
unit Generics.Nullable;

interface

type
  TNullable<T> = record
  private
    FValue: T;
    FIsNil: Boolean;
  public
    class operator Implicit(const Value: T): TNullable<T>;
    class operator Implicit(Value: Pointer): TNullable<T>;
    class operator Implicit(const Value: TNullable<T>): T;

    property IsNil: Boolean read FIsNil;
    property Value: T read FValue;
  end;

Pour plus d'infos sur les redéfinitions d'opérateurs, consultez le tutoriel La surcharge d'opérateurs sous Delphi 2006 Win32La surcharge d'opérateurs sous Delphi 2006 Win32 par Laurent Dardenne de Laurent Dardenne.

C'est donc un type immuable (dont on ne peut plus modifier l'état une fois qu'il est créé).

L'implémentation des trois opérateurs de conversion est assez simple. Le deuxième d'entre eux (celui avec un paramètre de type Pointer) est là pour permettre l'affectation := nil.

 
Sélectionnez
uses
  SysUtils;

resourcestring
  sCantConvertNil = 'Ne peut convertir nil';
  sOnlyValidValueIsNil = 'La seule valeur valide est nil';

class operator TNullable<T>.Implicit(const Value: T): TNullable<T>;
begin
  Result.FValue := Value;
  Result.FIsNil := False;
end;

class operator TNullable<T>.Implicit(Value: Pointer): TNullable<T>;
begin
  Assert(Value = nil, sOnlyValidValueIsNil);
  Result.FIsNil := True;
end;

class operator TNullable<T>.Implicit(const Value: TNullable<T>): T;
begin
  if Value.IsNil then
    raise EConvertError.Create(sCantConvertNil);

  Result := Value.FValue;
end;

On peut l'utiliser très simplement comme ceci :

 
Sélectionnez
var
  Value: Integer;
  NullValue: TNullable<Integer>;
begin
  NullValue := 5;
  WriteLn(Integer(NullValue));
  NullValue := nil;
  if NullValue.IsNil then
    WriteLn('nil')
  else
    WriteLn(NullValue.Value);

  NullValue := 10;
  Value := NullValue;
  WriteLn(Value);
end;

Ce qui affiche bien :

 
Sélectionnez
5
nil
10

Vous avez tout compris ? C'est génial, parce que je n'ai donné aucune explication. C'est bien la preuve que c'est simple comme bonjour, les génériques :-).

Le code source complet de Generics.Nullable se trouve dans le zip des sources de ce tutoriel, téléchargeable en fin de tutorielTélécharger les sources.


précédentsommairesuivant

Copyright © 2008 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.