Utilisation des espaces de nommage avec Delphi

De RAD Studio
Aller à : navigation, rechercher

Remonter à Programmes et unités - Index


Important : RAD Studio supporte désormais un nom de portée d'unité ou un préfixe en plus de l'espace de nommage ou du nom de l'unité. Pour qu'un nom soit considéré comme entièrement qualifié, le nom de portée d'unité doit être inclus. Pour de plus amples informations, voir Noms de portées d'unités.

Dans Delphi, une unité est le conteneur de base pour les types. Dans Delphi, un espace de nommage est un conteneur d'unités Delphi.

Contrairement aux unités Delphi traditionnelles, les espaces de nommage peuvent être imbriqués pour former une hiérarchie de contenance. Les espaces de nommage imbriqués permettent d'organiser les identificateurs et les types, mais aussi d'éviter les ambiguïtés avec les types ayant le même nom. Puisqu'ils font office de conteneur pour les unités Delphi, les espaces de nommage peuvent aussi être utilisés pour faire la différence entre des unités de même nom qui résident dans des packages différents.

Par exemple, la classe MyClass de MyNameSpace, est différente de la classe MyClass de YourNamespace.

Cette rubrique aborde les sujets suivants :

  • Espaces de nommage par défaut des projets et déclaration d'espace de nommage.
  • Portée de recherche des espaces de nommage.
  • Utilisation des espaces de nommage dans les unités Delphi.

Déclaration des espaces de nommage

Dans RAD Studio, un fichier projet (program, library ou package) introduit implicitement son propre espace de nommage, appelé espace de nommage par défaut du projet. Une unité peut être un membre de l'espace de nommage par défaut du projet ou peut se déclarer explicitement elle-même comme membre d'un autre espace de nommage. Dans les deux cas, l'unité déclare son appartenance à un espace de nommage dans l'en-tête d'unité. Par exemple, prenez la déclaration explicite d'espace de nommage suivante :

unit MyCompany.MyWidgets.MyUnit;

Remarquez que les différentes parties de l'espace de nommage sont séparées par des points. Les espaces de nommage n'introduisent pas de nouveaux symboles d'identificateurs entre les points ; les points font partie du nom de l'unité. Dans cet exemple, le nom du fichier source est MyCompany.MyWidgets.MyUnit.pas et le nom du fichier de destination compilé est MyCompany.MyWidgets.MyUnit.dcu.

Remarquez aussi que les points impliquent l'imbrication conceptuelle, ou contenance, d'un espace de nommage dans un autre. L'exemple ci-dessus déclare l'unité MyUnit comme un membre de l'espace de nommage MyWidgets qui, à son tour, est contenu dans l'espace de nommage MyCompany. Rappelons à nouveau que cette contenance n'est fournie que dans un objectif de documentation.

L'espace de nommage par défaut d'un projet déclare un espace de nommage pour toutes les unités du projet. Considérez les déclarations suivantes :

Program MyCompany.Programs.MyProgram;
Library MyCompany.Libs.MyLibrary;
Package MyCompany.Packages.MyPackage;

Ces instructions établissent respectivement l'espace de nommage par défaut de program, library et package. L'espace de nommage est déterminé en supprimant l'identificateur le plus à droite (et le point) de la déclaration.

Une unité qui omet un espace de nommage explicite est appelée unité générique. Une unité générique est automatiquement membre de l'espace de nommage par défaut du projet. Si l'on reprend la déclaration program précédente, la déclaration d'unité suivante force le compilateur à traiter MyUnit comme un membre de l'espace de nommage MyCompany.Programs.

unit MyUnit;

L'espace de nommage par défaut du projet n'affecte pas le nom du fichier source Delphi d'une unité générique. Dans l'exemple précédent, le fichier source Delphi s'appelle MyUnit.pas. La même règle s'applique au nom du fichier dcu. Dans notre exemple, le fichier dcu résultant serait MyUnit.dcu.

Les chaînes des espaces de nommage ne tiennent pas compte de la casse. Le compilateur considère que deux espaces de nommage sont équivalents s'ils ne diffèrent que par la casse. En revanche, il préserve la casse d'un espace de nommage et l'utilise dans le nom des fichiers de destination, les messages d'erreur et les identificateurs d'unité RTTI. Les RTTI des noms de classes et de types incluent la spécification complète de l'espace de nommage.

Recherche d'espaces de nommage

Une unité doit déclarer les autres unités dont elle dépend. Le compilateur doit rechercher les identificateurs dans ces unités. Pour les unités placées dans des espaces de nommage explicites, la portée de recherche est déjà connue, mais pour les unités génériques, le compilateur doit établir une portée de recherche d'espace de nommage.

Prenez les déclarations unit et uses suivantes :

unit MyCompany.ProjectX.ProgramY.MyUnit1;
uses MyCompany.Libs.Unit2, Unit3, Unit4;

Ces déclarations établissent MyUnit1 comme membre de l'espace de nommage MyCompany.ProjectX.ProgramY. MyUnit1 dépend des 3 unités suivantes : MyCompany.Libs.Unit2 et les unités génériques Unit3 et Unit4. Le compilateur peut résoudre les noms d'identificateurs dans Unit2, car la clause uses a spécifié le nom complet de l'unité. Pour résoudre les noms d'identificateurs dans Unit3 et Unit4, le compilateur doit établir un ordre de recherche d'espace de nommage.

Portée de recherche d'espace de nommage

Les emplacements de recherche peuvent venir de trois sources possibles : les options du compilateur, l'espace de nommage par défaut du projet et l'espace de nommage de l'unité en cours.

Le compilateur résout les noms d'identificateurs dans l'ordre suivant :

  1. L'espace de nommage de l'unité en cours (le cas échéant).
  2. L'espace de nommage par défaut du projet (le cas échéant).
  3. Les espaces de nommage spécifiés par les options du compilateur.

Exemple de recherche d'espace de nommage

Les exemples de fichiers de projet et d'unité suivants indiquent l'ordre de recherche de l'espace de nommage :

// Project file declarations...
program MyCompany.ProjectX.ProgramY;

// Unit source file declaration...
unit MyCompany.ProjectX.ProgramY.MyUnit1;

Etant donné cet exemple de programme, le compilateur recherche les espaces de nommage dans l'ordre suivant :

  1. MyCompany.ProjectX.ProgramY
  2. MyCompany.ProjectX
  3. Les espaces de nommage spécifiés par les options du compilateur.

Si l'unité en cours est générique (c'est-à-dire qu'elle n'a pas de déclaration d'espace de nommage explicite dans son instruction unit), la résolution commence par l'espace de nommage par défaut du projet.

Utilisation des espaces de nommage

La clause uses Delphi amène un module dans le contexte de l'unité en cours. La clause uses doit faire référence à un module par son nom complet (c'est-à-dire en incluant la spécification complète de l'espace de nommage) ou par son nom générique, en utilisant donc les mécanismes de résolution des espaces de nommage pour localiser l'unité.

Noms complets d'unités

L'exemple suivant illustre la clause uses avec les espaces de nommage :

unit MyCompany.Libs.MyUnit1;
uses MyCompany.Libs.Unit2,  // Fully qualified name.
  UnitX;                   // Generic name.

Une fois le module amené dans le contexte, le code source peut faire référence aux identificateurs de ce module avec le nom non qualifié ou avec le nom complet (si nécessaire, pour supprimer l'ambiguïté d'identificateurs portant le même nom dans des unités différentes). Les instructions Writeln suivantes sont équivalentes :

uses MyCompany.Libs.Unit2;

begin
  Writeln(MyCompany.Libs.Unit2.SomeString);
  Writeln(SomeString);
end.

Un identificateur complet doit inclure la spécification complète de l'espace de nommage. Dans l'exemple précédent, faire référence à SomeString en n'utilisant qu'une partie de l'espace de nommage serait une erreur :

Writeln(Unit2.SomeString);       // ERROR!
Writeln(Libs.Unit2.SomeString);  // ERROR!
Writeln(MyCompany.Libs.Unit2.SomeString);      // Correct.
Writeln(SomeString);                           // Correct.

Vous ne pouvez pas non plus ne faire référence qu'à une partie d'un espace de nommage dans la clause uses. Il n'existe aucun moyen d'importer toutes les unités et tous les symboles dans un espace de nommage. Le code suivant n'importe pas tous les symboles et unités dans l'espace de nommage MyCompany :

uses MyCompany;   // ERROR!

Cette restriction s'applique aussi à l'instruction with-do. Le code suivant provoque une erreur de compilation :

with MyCompany.Libs do    // ERROR!

Espaces de nommage multi-unités

Plusieurs unités peuvent appartenir au même espace de nommage si les déclarations d'unités se réfèrent au même espace de nommage. Par exemple, une personne peut créer deux fichiers, unit1.pas et unit2.pas, avec les déclarations d'unités suivantes :

// in file 'unit1.pas'
unit MyCompany.ProjectX.ProgramY.Unit1

// in file 'unit2.pas'
unit MyCompany.ProjectX.ProgramY.Unit2

Dans cet exemple, l'espace de nommage MyCompany.ProjectX.ProgramY contient logiquement tous les symboles interface de unit1.pas et unit2.pas.

Dans un espace de nommage, les noms de symbole doivent être uniques d'une unité à une autre. Dans l'exemple ci-dessus, c'est une erreur pour Unit1 et Unit2 de définir toutes les deux un symbole d'interface global nommé mySymbol.

Les unités individuelles agrégées dans un espace de nommage ne sont pas disponibles pour le code source sauf si elles sont explicitement utilisées dans la clause uses du fichier. En d'autres termes, si un fichier n'utilise que l'espace de nommage, les expressions d'identificateurs complets faisant référence à un symbole dans une unité de cet espace de nommage doivent utiliser le nom de l'espace de nommage, et pas seulement le nom de l'unité définissant ce symbole.

Il se peut qu'une clause uses fasse référence à un espace de nommage ainsi qu'à des unités individuelles de cet espace de nommage. Dans ce cas, une expression complète faisant référence à un symbole de l'unité spécifique indiquée dans la clause uses peut utiliser le véritable nom d'unité ou le nom complet (incluant l'espace de nommage et le nom de l'unité) du qualificateur. Les deux formes de référence sont identiques et désignent le même symbole.

Remarque : L'utilisation explicite d'une unité dans la clause uses fonctionne uniquement lorsque vous compilez à partir de fichiers source ou dcu. Si les unités d'espace de nommage sont compilées dans un assemblage alors que ce dernier est référencé par le projet au lieu des unités individuelles, le code source qui se réfère explicitement à une unité de l'espace de nommage échoue.

Voir aussi