I. Introduction▲
Le but de cet article n'est pas d'expliquer ce qu'est .NET, il y a une présentation ici par Microsoft, mais de présenter ce qu'il va être possible de faire avec Delphi for .NET et ce que j'ai pu tester.  Avec Delphi 7, le compilateur en ligne de commande (dccil) ainsi que les premières unités de ce qui sera la VCL for .NET sont livrés. Il est donc dès à présent possible de commencer à tâter le terrain de ce que sera l'avenir de Delphi sur cette plateforme. Le produit final dont le nom de code est Galileo sera disponible courant 2003.
II. Le Hello World▲
Pour commencer un programme simple :
program HelloWorld;
{$APPTYPE CONSOLE}
begin
Writeln('Hello World in Delphi for .NET');
end.
On compile le programme avec le compilateur en ligne de commande dccil qui va produire un exécutable contenant du code MSIL (MicroSoft Intermediate Language) conforme comme on peut le vérifier avec le programme peverify livré avec le SDK .NET.
Mais à partir de cette preview, il est aussi possible d'accéder au framework .NET. Voici une application simple l'utilisant :
unit Main_frm;
interface
uses
System.Windows.Forms,
System.Drawing;
type
TfrmMain = class(Form)
private
btnOk: Button;
procedure InitializeComponents;
public
constructor Create;
procedure btnOkClick(Sender: TObject; E: EventArgs);
end;
implementation
{ TfrmMain }
procedure TfrmMain.btnOkClick(Sender: TObject; E: EventArgs);
begin
MessageBox.Show('Coucou', 'Delphi for .NET preview');
end;
constructor TfrmMain.Create;
begin
inherited Create;
InitializeComponents;
end;
procedure TfrmMain.InitializeComponents;
begin
btnOk := Button.Create;
btnOk.Parent := Self;
btnOk.Location := Point.Create(10,10);
btnOk.Size := Size.Create(200,25);
btnOk.Text := 'Coucou';
btnOk.add_Click(btnOkClick);
end;
end.
program GUI;
uses
System.Windows.Forms,
Main_frm in 'Main_frm.pas';
begin
Application.Run(TfrmMain.Create);
end.
Dans cet exemple, on crée à partir des classes du framework .NET une application fenêtrée. On déclare une classe dérivant de System.Windows.Forms.Form avec un bouton (System.Windows.Forms.Button). Dans le constructeur de la fiche on va initialiser notre composant bouton (taille, position, texte, etc.) et on va lui ajouter un gestionnaire d'événement avec la méthode add_Click correspondant à l'événement Click. On remarque ici la gestion par ressources de Delphi est quand même beaucoup plus pratique qu'une initialisation par code… ;-)
On obtient donc une application fenêtrée plutôt rapidement en utilisant seulement le framework .NET. Il est donc plus simple avec .NET de créer de telles applications qu'avec les API WIn32. On retrouve une programmation proche de la VCL au niveau du système.
Si vous compilez avec l'option -V, les informations de débogage sont incluses et il est possible d'utiliser le débogueur de la CLR (Common Language Runtime) DbgCLR fourni avec le Framework SDK (C:\Program Files\Microsoft.NET\FrameworkSDK\GuiDebug\DbgCLR.exe).
Menu Debug | Program To Debug, indiquez le programme que vous venez de compiler avec l'option -V. Puis ouvrez le fichier source Pascal que vous voulez déboguer. Posez un point d'arrêt (F9) à la ligne qui vous intéresse et lancez le programme sous contrôle du débogueur (F5). Le programme s'arrêtera sur le point d'arrêt.
Vous pouvez alors faire du pas à pas (Step Over, F10) ou du pas à pas approfondi (Step In, F11).
III. Les unités et le Framework .NET▲
La compilation des unités Delphi produit maintenant un fichier .dcuil. À chaque fois que l'on fait un uses dans un programme on a besoin du fichier .dcuil associé. Cela signifie que dans notre exemple, lorsque l'on fait uses System.Windows.Forms; il faut le fichier System.Windows.Forms.dcuil. Le compilateur dccil est livré avec ces fichiers dcuil pour l'ensemble du framework .NET. Avec ces dcuil, il existe des fichiers .dcua qui représentent une description des assemblies contenues dans le namespace du dcuil. Le compilateur examine le fichier dcua pour savoir quel dcuil il doit recompiler quand une assembly a changé.
Il est maintenant possible de créer des namespaces pour les unités :
unit MyCompany.MyApplication.MyForm;
interface
implementation
end.
Cette unité sera par exemple compilée en MyCompany.MyApplication.MyForm.dcuil et on l'utilisera de la façon suivante :
program MyApplication;
uses MyCompany.MyApplication.MyForm;
begin
end.
Il est possible et parfois nécessaire de préfixer par le namespace entier certains identificateurs :
type
TfrmMain = class(Form)
private
lblName: System.Windows.Forms.Label;
procedure InitializeComponents;
public
constructor Create;
end;
var
AType: System.Type;
Label et type étant des mots réservés du langage Pascal, il est important de préciser le namespace pour indiquer au compilateur que ce n'est pas l'utilisation du mot réservé, mais d'un type du framework .NET.
Puisque les dcuil du framework .NET sont livrés avec le compilateur, vous avez à disposition des milliers de classes prêtes à l'emploi et que je vous invite à explorer. Vous avez la référence de ces classes ici: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/cpref_start.asp
Les exécutables produits par dccil s'exécutant maintenant dans l'environnement managed de la CLR, la libération des objets se fait automatiquement par le Garbage Collector. En général, il n'est donc plus nécessaire d'appeler Free ou de définir un destructor. Pour des questions de compatibilité du code existant, Free est toujours défini et peut être appelé, mais la libération mémoire de l'objet n'est pas assurée après cet appel. Néanmoins, il est nécessaire de libérer dans les destructors les ressources qui ne seraient pas managed, c'est-à -dire non prises en compte par la CLR.
La classe TObject est maintenant aliasée sur le System.Object du framework .NET ce qui permet d'avoir une interaction plus homogène avec le reste du framework. De même, les types de base du Pascal vont correspondre aux types de la CLR.
IV. Les Class Helpers▲
La création d'un nouveau compilateur pour l'environnement .NET a permis d'introduire des nouveautés dans le langage. L'une des plus puissantes qui m'a été donné de voir est celle des class helpers. Cette technique a été ajoutée pour répondre à la problématique de compatibilité entre la VCL Win32 et le framework .NET. La classe TObject, ancêtre de toutes classes en Delphi est maintenant définie comme étant la classe System.Object de .NET. Or la classe .NET ne possède pas les méthodes du TObject que l'on avait avec la version Win32. Pour pallier ce manque, Borland a créé une construction que l'on appelle Class Helper permettant d'élargir la portée d'une classe avec les méthodes définies dans le class helper.
Voyons cela sur un exemple concret :
program ClassHelperExample;
{$APPTYPE CONSOLE}
type
TMyClass = class(TObject)
public
procedure AMethod;
end;
TMyClassHelper = class helper for TMyCLass
procedure AClassHelperMethod;
end;
{ TMyClass }
procedure TMyClass.AMethod;
begin
Writeln('TMyClass.AMethod');
end;
{ TMyClassHelper }
procedure TMyClassHelper.AClassHelperMethod;
begin
Writeln('TMyClassHelper.AClassHelperMethod');
end;
var
MyClass: TMyClass;
begin
MyClass := TMyClass.Create;
MyClass.AMethod;
MyClass.AClassHelperMethod;
end.
On déclare tout d'abord, une classe TMyClass avec une méthode AMethod. Puis on déclare un class helper TMyClassHelper pour la classe TMyClass. Dans ce class helper on déclare une méthode AClassHelperMethod. On implémente cette dernière comme faisant partie de la classe TMyClassHelper, mais en réalité elle va pouvoir être appelée à partir d'une instance de TMyClass comme on le voit dans le programme principal.
Voyons alors, avec ce mécanisme, ce que donne l'implémentation de TObject pour Delphi for .NET :
type
TObject = System.Object;
TObjectHelper = class helper for TObject
procedure Free;
class function ClassType: TClass;
class function ClassName: string;
class function ClassNameIs(const Name: string): Boolean;
class function ClassParent: TClass;
class function ClassInfo: TObject;
class function InheritsFrom(AClass: TClass): Boolean;
class function MethodAddress(const Name: string): TObject;
function FieldAddress(const Name: string): TObject;
procedure Dispatch(var Message: TObject);
procedure DefaultHandler(var Message: TObject);
end;
TObject bénéficie ainsi de toutes les méthodes définies dans System.Object du framework .NET plus les méthodes définies dans le class helper. Bien sûr, toutes les classes descendantes de TObject en bénéficient aussi.
Il est aussi possible d'hériter d'un autre helper class.
TAnotherClassHelper = class helper(TMyClassHelper) for TMyCLass
procedure AnotherClassHelperMethod;
end;
Nous avons vu le principe de base des class helpers, à vous maintenant d'explorer les comportements en essayant différentes combinaisons sur des exemples comme ci-dessus.
V. Les nouveautés du langage▲
Comme l'environnement d'exécution qu'est .NET demande un code dit safe, certaines constructions deviennent non valides et obsolètes pour Delphi for .NET comme les pointeurs et tout ce qui se rapporte directement à la mémoire, les allocations de mémoire (GetMem, FreeMem, ReallocMem) les fichiers typés, les transtypages dans des types incompatibles, etc. Delphi 7 intègre des avertissements quant à la nature safe du code que vous compilez pour Win32. Ces avertissements peuvent être activés pour tester la qualité de votre code en vue d'être porté vers .NET.
En plus des class helpers que l'on a vues précédemment, Delphi for .NET intégrera d'autres nouveautés, qui sont pour l'instant encore en recherche. En vrac on peut citer :
- les méthodes et classes finales (non héritables) ;
- les types imbriqués (définir une classe dans une autre) ;
- méthodes dans les records (mais non virtuelles). Les records deviennent ainsi des objets automatiques (sans allocation dynamique, mais sur la pile) ;
- variables de classe (static)Â ;
- propriétés de classe (static) ;
- gestionnaires d'événement multiples (Include et Exclude seront surchargés pour ajouter ou retirer un gestionnaire) ;
- surcharge de propriétés (property overload) ;
- etc.
VI. Conclusion▲
Le compilateur Delphi for .NET livré avec Delphi 7 est une version que l'on pourrait encore qualifier d'alpha. Il reste beaucoup de choses à implémenter, mais on peut déjà commencer à jouer avec et à utiliser les classes du framework .NET ce qui est déjà énorme ! Cela donne un bon avant-goût de ce que sera Galileo courant 2003 et on espère une compatibilité proche de la VCL pour migrer facilement les applications vers cette nouvelle plateforme.