I. Public concerné▲
Testé sous Dot Net 1.1 avec les spécifications du C# v1.2 et Delphi 2005.
Version 1.0
Je tiens à remercier Nono40, Pascal Jankowski et Sébastien Doeraene (sjrd) pour leurs relectures et suggestions pertinentes ainsi que pour leurs corrections orthographiques.
Cet article utilise quelques URL locales vers la documentation de .NET de Microsoft et de Delphi 2005.
II. Introduction▲
Étant en phase d'apprentissage sur le langage Delphi 2005 pour .NET, j'ai très vite compris que la conversion des exemples issus du SDK allait poser quelques problèmes aux nombreux débutants.
Cette approche peut paraître paradoxale, mais la compréhension du langage C# m'a, tout compte fait, rendu service même si cela a été un peu délicat dans les premiers temps. Il ne s'agit pas ici d'un cours complet sur le C# ni sur Delphi pour .NET, mais d'une suite d'indications. Le contexte pouvant influencer la conversion d'un code C# vers Delphi pour .NET.
Il va sans dire que cet article n'est pas exhaustif sur le sujet et sera mis à jour régulièrement, vos remarques et propositions y contribueront.
Concernant le C#, j'ai le plus souvent utilisé la terminologie propre au SDK.
Le symbole NI signifie fonctionnalité non implémentée en Delphi pour .Net.
Attention, certaines possibilités du langage C# ne sont pas compatibles avec la CLS.
Extrait du SDK :
Pour interagir entièrement avec d'autres objets, quel que soit le langage dans lequel ils ont été implémentés, les objets ne doivent exposer aux appelants que les fonctionnalités qui sont communes à tous les langages avec lesquels ils doivent fonctionner. Pour cette raison, un ensemble de fonctionnalités de langage appelé spécification CLS (Common Language Specification), qui comprend les fonctionnalités de langage de base nécessaires à de nombreuses applications, a été défini.
Il est donc conseillé de n'utiliser que le C# CLS Compliant. L'ajout de l'attribut personnalisé CLSCompliant indique au compilateur de vérifier si le code généré respecte bien les spécifications de la CLS.
Extrait du SDK :
Afin qu'un module soit conforme CLS, via [module:System.CLCSompliant(true)], il doit être généré avec l'option
/target:module du compilateur.
Pour ceux qui souhaiteraient aborder plus en détail la comparaison entre le langage C# et le langage Delphi pour .NET, consultez le cours complet sur le C# de RM di Scala .
Vous trouverez ici quelques liens utiles glanés au cours de ma rédaction qui vous permettront d'aborder plus précisément certains points :
Anders Hejlsberg : une courte biographie d'un des concepteurs du C# et de Delphi.
The C# Design Process : A Conversation with Anders Hejlsberg.
Pages Microsoft dédiées au langage C# notamment les spécifications 2.0.
Un cours complet sur le C# par RM di Scala.
Un second cours complet sur le C# (lien direct sur un fichier au format Pdf).
Conversion C# vers Delphi : un outil Borland en version BETA, sa version en add-in pour l'IDE Delphi 2005.
Conversion C++ vers C#
III. Modificateur de types et de membres de types▲
Ils permettent de modifier les déclarations des types et membres de types.
III-A. Modificateurs d'accès▲
Le compilateur Delphi pour .NET prend en charge des paramètres de visibilité supplémentaires conformes à la spécification CLS (Common Language Specification) .NET.
C# |
Delphi .NET |
Commentaire |
---|---|---|
public |
public |
C# : L'accès n'est pas limité. |
protected |
protected |
C# : L'accès est restreint à la classe conteneur ou aux types dérivés de la classe conteneur. |
protected internal |
strict protected |
C# : L'accès est restreint à l'assembly en cours ou aux types dérivés de la classe conteneur. |
private |
private |
C# : L'accès est restreint au type conteneur. |
internal |
strict private |
C# : L'accès est restreint à l'assembly en cours. Les membres internes sont accessibles seulement dans les fichiers du même assembly. |
Par défaut dans une classe en C# tous les membres sans qualificateur d'accès sont considérés comme privés (private).
Les types imbriqués, qui sont membres d'autres types, peuvent disposer d'accessibilités déclarées, voir « Guide de référence du programmeur C# » proposé dans l'aide de Delphi 2005.
À noter sous Delphi .Net :
Published : accessible à tout le code et depuis l'inspecteur d'objets ;
Automated n'est plus supporté en .NET.
III-B. Autres modificateurs▲
C# |
Delphi .NET |
Commentaire |
---|---|---|
static |
class |
C# : Utilisez le modificateur static pour déclarer un membre statique, qui appartient au type lui-même plutôt qu'à un objet spécifique. |
static extern |
external |
C# : Les méthodes externes sont implémentées en externe, en utilisant généralement un langage autre que C#. |
virtual |
virtual |
C# : Lorsqu'une déclaration de méthode d'instance comprend un modificateur virtual, cette méthode est une méthode virtuelle. |
abstract |
abstract |
C# : Le modificateur abstract est utilisé pour une méthode ou une propriété d'une classe qui n'a pas d'implémentation ou pour une classe qui comprend des méthodes de ce type. |
overload |
C# : La surcharge existe, mais il n'existe pas de mot clé associé. La liste d'arguments différents pour des méthodes de même nom détermine la surcharge. |
|
override |
C# : Fournit une nouvelle implémentation d'un membre virtuel hérité d'une classe de base. Il n'existe pas de mot clé pour préciser la surcharge. |
|
const |
const |
C# : Spécifier que la valeur du champ ou la variable locale ne peut pas être modifiée. |
readonly |
NI |
C# : Déclarer un champ auquel seules peuvent être attribuées des valeurs au sein de la déclaration ou dans un constructeur de la même classe. |
sealed |
sealed |
C# : Spécifier qu'une classe ne peut pas être héritée. |
unsafe |
NI |
C# : Déclarer un contexte non sécurisé. |
volatile |
NI |
C# : Indiquer qu'un champ peut être modifié dans le programme par quelque chose tel que le système d'exploitation, le matériel ou un thread s'exécutant simultanément. |
III-B-1. Exemple de procédure external▲
[DllImport(
"kernel32"
, SetLastError=true)]
static
extern
bool
CreateDirectory
(
string
name,
SecurityAttribute sa);
[DllImport('user32.dll'
, SetLastError=true
)]
function
CreateDirectory(name: string
; sa : SecurityAttribute):Boolean
; external
;
III-B-2. Exemple d'initialisation de champ statique▲
using
System;
class
Test
{
static
void
Main
(
) {
Console.
WriteLine
(
"{0} {1}"
,
B.
Y,
A.
X);
}
public
static
int
F
(
string
s) {
Console.
WriteLine
(
s);
return
1
;
}
}
class
A
{
public
static
int
X =
Test.
F
(
"Init A"
);
}
Dans ce cas sous Delphi, on utilisera une variable de classe :
A=Class
Public
// champs de classe, static
Class
var
X : Integer
;
end
;
Le code suivant qui contient du code dans la déclaration du type :
public
static
readonly
DBBool dbNull =
new
DBBool
(
0
);
est convertie en utilisant un constructeur de classe.
TDBBool = record
Strict
private
// Champ privé pour stocker la valeur du type
FValeur : integer
;
// champs de classe, static
Class
var
FdbNull : TDBBool;
Class
Constructor
CCreate;
Private
// Le constructeur ne doit pas être accessible
// Private pour TDBBool.dbTrue:=TDBBool.Create(0);
Constructor
Create(AValeur: DBType);
...
end
;
implementation
Constructor
TDBBool.Create(AValeur: DBType);
Begin
FValeur:=AValeur;
end
;
Class
Constructor
TDBBool.CCreate;
Begin
// Initialise les valeurs possibles du type
TDBBool.FdbNull.FValeur:=cdbNull;
end
;
Vous trouverez ici la conversion du code complet de cet exemple de classe en C#.
IV. Opérateurs▲
Catégorie d'opérateurs |
C# |
Delphi .NET |
Commentaire |
---|---|---|---|
Arithmétique |
+ , - , * , / , % (modulo) |
+ , - , * , / et div , mod |
C# : |
Logique binaire |
&, |, ^, !, ~ |
AND, OR, XOR, NOT, NOT |
C# : L'opérateur ~ effectue une opération de complément de bits sur son opérande. Les opérateurs de complément de bits sont prédéfinis pour int, uint, long et ulong. |
Logique booléen |
&&, ||, true, false |
AND, OR, TRUE, FALSE |
|
Concaténation de chaînes |
+ |
+ |
|
Incrément, décrément |
++, -- |
Inc(), Dec() |
|
Déplacement |
<<, >> |
Shl, Shr |
L'opérateur de déplacement vers la gauche (<<) ou la droite (>>) déplace le premier opérande vers la gauche ou la droite du nombre de bits spécifié par le second opérande. |
Relationnel |
==, !=, <, >, <=, >= |
=, <>, <, >, <=, >= |
C# : |
Assignation |
=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= |
:=, Inc(), Dec(), NI, idem,… |
C# : Une expression de la forme x ^= y |
Accès au membre |
. , this |
. , Self |
L'opérateur point (.) est utilisé pour l'accès aux membres. |
Indexation |
[] |
[] |
|
Cast |
datatype() |
datatype() |
|
Conditionnel |
?: |
If Then Else |
L'opérateur conditionnel est associatif à droite. |
Concaténation et suppression de délégué |
+, - |
Include, Exclude |
|
Création d'objets |
new |
Create |
voir aussi le chapitre : Structure de données-tableaux |
Informations de type |
as, is, sizeof, typeof |
AS, IS, SIZEOF, NI |
C# : L'opérateur typeof permet d'obtenir l'objet System.Type pour un type. Il peut être remplacé par l'appel de la méthode GetType. |
Contrôle des exceptions de dépassement de capacité |
checked, unchecked |
Directives de compilation |
C# : Dans un contexte non vérifié (unchecked), si une expression produit une valeur qui est hors de la plage du type de destination, le résultat est tronqué. |
Adresse et adressage indirect |
*, ->, [], & |
Pointer, Pointer^.x, incrément d'adresse,@ |
Il s'agit d'instructions spécifiques à Win32, générant du code non sécurisé. |
Ensemble |
enum |
Set of type |
C# : Voir les méthodes de la classe enum |
La surcharge d'opérateurs en C# :
public
static
implicit
operator
DBBool
(
bool
x)
La surcharge d'opérateurs en Delphi .Net :
Class
operator TDBBool.Explicit(x: TDBBool): Boolean
;
Les opérateurs true et false du C# ne peuvent être surchargés sous Delphi .NET.
V. Types▲
Les types sont communs aux deux langages s'ils sont 'mappés' sur les types de System.xxx.
Sous Delphi 2005 pour .Net certains types sont des alias et d'autres des simulations.
Soyez attentif au fait que le comportement d'un code C#, particulièrement au niveau des types, peut dépendre :
- de directives de compilation, notamment /checked ;
- de convention de conversion, implicite ou explicite, différente.
VI. Tests▲
VI-A. ?:▲
L'expression évaluée doit avoir un résultat booléen en C#.
a ?
b :
c ?
d :
e
If
a=true
then
b
else
if
c=true
then
d
else
e
VI-B. switch▲
L'instruction de contrôle switch est convertie en case of. La partie default est convertie en else. En C# l'instruction break indique la fin de la branche case, s'il n'y a pas de break l'exécution continue au cas suivant.
public
override
string
ToString
(
)
{
switch
(
value
)
{
case
-
4
case
-
3
case
-
2
:
Console.
writeline
(
"Exemple"
);
Break;
case
-
1
:
return
"DBBool.False"
;
case
0
:
return
"DBBool.Null"
;
case
1
:
return
"DBBool.True"
;
default
:
throw
new
InvalidOperationException
(
);
}
}
Function
TDBBool.ToString: String
;
begin
Case
Fvaleur of
-4
,
-3
,
-2
: begin
Console.writeline("Exemple");
end
;
-1
: begin
Result:='TDBBool.False'
;
Exit;
end
;
0
: begin
Result:='TDBBool.Null'
;
Exit;
end
;
1
: begin
Result:='TDBBool.True'
;
Exit;
end
;
else
Raise
InvalidOperationException.Create;
end
;
end
;
Dans ce dernier exemple Delphi, l'instruction Exit est nécessaire pour refléter exactement l'instruction return contenue dans le code C#.
VI-C. Test de validité sur des pointeurs (null)▲
if
(
EventTest !=
null
)
EventTest
(
this
,
new
EventArgs
(
));
Attention sous Delphi NULL est une fonction de Borland.Vcl.Variants permettant d'obtenir un variant Null.
Utilisez la constante prédéfinie nil.
Toute variable procédurale peut contenir la valeur nil, ce qui signifie qu'elle ne pointe sur rien. Pour tester si une variable procédurale est initialisée, utilisez la fonction standard Assigned
if
Assigned(FEventTest) then
FEventTest(Self
, EventArgs.Create);
VII. Structures itératives▲
VII-A. While▲
public
static
void
Main
(
)
{
int
n =
1
;
while
(
n <
6
) do
{
Console.
WriteLine
(
"la valeur courante de n est {0}"
,
n);
n++;
}
}
procedure
Main;
var
n: integer
;
begin
n:= 1
;
while
(n < 6
)
begin
WriteLn('la valeur courante de n est '
, n);
inc(n);
end
;
end
;
VII-B. Do/While▲
public
static
void
Main (
)
{
int
x;
int
y =
0
;
do
{
x =
y++;
// post-incrémentation
Console.
WriteLine
(
x);
}
while
(
y <
5
);
}
procedure
Main;
var
x, y : integer
;
begin
y:=0
;
Repeat
x:=y;
inc(y);
Console.WriteLine(x);
Until
(y >= 5
);
end
;
Ici prenez garde à l'inversion du test.
VII-C. For▲
for
(
int
i =
1
;
i <=
10
;
i++
)
{
Console.
WriteLine
(
i);
}
Var
i: integer
;
Begin
for
i := 1
to
10
do
begin
Console.WriteLine(i);
end
;
VII-D. Foreach▲
// Utilisation avec les tableaux
using
System;
class
MainClass
{
public
static
void
Main
(
)
{
int
odd =
0
,
even =
0
;
int
[]
arr =
new
int
[]
{
0
,
1
,
2
,
5
,
7
,
8
,
11
};
foreach
(
int
i in
arr)
{
if
(
i%
2
==
0
)
even++;
else
odd++;
}
Console.
WriteLine
(
"Trouvé {0} chiffre impair et {1} chiffre pair."
,
odd,
even) ;
}
}
Sous Delphi .NET on utilise un tableau multidimensionnel alloué dynamiquement.
var
i, odd, even : integer
;
arr : Array
of
integer
;
Begin
odd:= 0
;
even:=0
;
arr:= New(array
[] of
integer
,(0
,1
,2
,5
,7
,8
,11
));
For
i in
arr Do
if
(i mod
2
= 0
)
then
inc(even)
else
inc(odd);
WriteLn('Trouvé '
+ intToStr(odd)+' chiffre impair et '
+intToStr(even)+' chiffre pair.'
) ;
Readln;
end
;
Delphi pour .NET prend en charge l'itération du style for-element-in-collection sur les conteneurs. Les modèles suivants d'itérations sur les conteneurs sont reconnus par le compilateur :
- for Element in ArrayExpr do Instruction ;
- for Element in StringExpr do Instruction ;
- for Element in SetExpr do Instruction ;
- for Element in CollectionExpr do Instruction.
Pour utiliser la construction de boucle for-in sur une classe, cette dernière doit implémenter un modèle de collection prescrit. Consulter la documentation pour les détails de l'implémentation.
VII-E. Rupture de séquence▲
VII-E-1. Break▲
Comportement identique
C# : l'instruction 'break' termine la boucle englobante la plus proche où l'instruction switch apparaît.
Delphi .Net : la procédure 'break' fait quitter le flux de contrôle d'une instruction for, while ou repeat et passe à la prochaine instruction qui suit l'instruction de boucle.
VII-E-2. Continue▲
Comportement identique
C# : L'instruction 'continue' transmet le contrôle à l'itération suivante de l'instruction d'itération englobante où elle apparaît.
Delphi .Net : La procédure 'continue' poursuit le flux de contrôle jusqu'à la prochaine itération d'une instruction for, while ou repeat.
VII-E-3. Exit▲
Attention homonymie et comportement différent
C# : Termine le processus et donne au système d'exploitation sous-jacent le code de sortie spécifié.
Delphi .Net : La procédure 'Exit' fait immédiatement passer le contrôle d'exécution en dehors de la procédure. Si la procédure en cours correspond au programme principal, Exit termine l'exécution du programme.
VIII. Exception▲
VIII-A. Déclencher une exception▲
public
static
explicit
operator
bool
(
DBBool x)
{
if
(
x.
value
==
0
) throw
new
InvalidOperationException
(
);
return
x.
value
>
0
;
}
Class
operator TDBBool.Explicit(x: TDBBool): Boolean
;
const
cdbNull=0
;
cdbTrue=1
;
begin
If
x.FValeur=cdbNull
then
raise
InvalidOperationException.Create
else
Result:=x.FValeur=cdbTrue;
end
;
VIII-B. Gestion d'une exception▲
public
override
bool
Equals
(
object
o)
{
try
{
return
(
bool
) (
this
==
(
DBBool) o);
}
catch
{
return
false
;
}
}
Function
TDBBool.Equals(x: TObject):Boolean
;
begin
try
Result:= (Self
= x as
TDBBool);
except
Result:=False
;
end
;
end
;
VIII-C. Redéclencher une exception▲
Une instruction throw peut être utilisée dans le bloc catch pour lever une nouvelle fois l'exception qui a été interceptée par l'instruction catch.
Par exemple :
try
...
catch
(
InvalidCastException e)
{
Console.
WriteLine
(
"b est NULL"
)
throw
(
e);
// Redéclenche l'exception e avec ses paramètres
}
try
...
except
On
E:InvalidOperationException do
begin
Console.WriteLine('b est NULL'
)
Raise
; // L'exception concernée, ici E, est implicite
end
;
end
;
En C# on peut redéclencher une exception sans les paramètres : throw.
En Delphi .Net cette possibilité n'existe pas.
VIII-D. Bloc finally▲
public
static
void
Main
(
)
{
int
i =
123
;
string
s =
"Une chaîne"
;
object
o =
s;
try
{
// conversion invalide ; o contient une string et pas un entier.
i =
(
int
) o;
}
finally
{
Console.
Write
(
"i = {0}"
,
i);
}
}
Procedure
Main()
var
i: integer
;
s: string
;
o: TObject;
begin
i:= 123
;
s:='Une chaîne'
;
o:=s;
try
// conversion invalide ; o contient une string et pas un entier.
i = integer
(o);
finally
Console.Write
('i = {0}'
, i);
end
;
end
;
IX. Classe▲
IX-A. Héritage▲
C# |
Delphi .NET |
Commentaire |
---|---|---|
class TopEvent : BaseEvent {… |
TForm1 = class(TForm) … |
IX-B. Constructeur▲
Le constructeur porte le même nom que la classe et en respectant la casse.
L'utilisation du mot clé this dans un constructeur indique l'appel du constructeur par défaut :
...
public
Initialise
(
Int32 n):
this
(
){
this
.
n =
n;
}
...
...
constructor
Initialise(n : integer
);
begin
inherited
Create; // En Delphi .NET l'appel de l'ancêtre est obligatoire.
Self
.n = n;
end
;
...
IX-C. Destructeur▲
La syntaxe suivante déclare un destructeur :
public
class
test{
...
~
Test
(
){
// Cleanup statements.
CloseHandle
(
Handle);
}
...
}
Identique au code :
public
class
test{
...
protected
override
void
Finalize
(
)
{
try
{
// Cleanup statements.
CloseHandle
(
Handle);
}
finally
{
base
.
Finalize
(
);
}
}
Le mot clé base est utilisé pour accéder aux membres de la classe de base à partir d'une classe dérivée et correspond au mot clé inherited sous Delphi.
Le code C# précédent correspond au code Delphi .NET suivant :
procedure
TTest.Finalize;
begin
try
CloseHandle(handle.ToInt32);
finally
inherited
;
end
end
;
IX-D. Type de membres▲
Les déclarations de classe peuvent contenir des déclarations pour des
- constantes ;
- champs ;
- méthodes ;
- propriétés ;
- événements ;
- indexeurs ;
- opérateurs ;
- constructeurs d'instance ;
- constructeurs statiques ;
- destructeurs ;
- types imbriqués.
L'initialisation de membres, dans la partie déclaration d'une classe, n'est pas possible sous Delphi .Net.
IX-E. Méthode▲
IX-E-1. Procédure▲
En C# le mot clé void indique une fonction ne renvoyant aucun résultat ce qui est le cas d'une procédure sous Delphi .NET.
void
UneMethode
(
);
Procedure
UneMethode;
IX-E-2. Fonction▲
Le mot clé return est remplacé par la combinaison de Result et d'Exit.
static
double
CalculateArea
(
int
r)
{
double
area;
area =
r*
r*
Math.
PI;
return
area;
}
function
CalculateArea(r: integer
):double
;
var
area : double
;
begin
area:= r*r*Math.PI;
Result:=area;
Exit;
end
;
IX-E-2-a. Fonction delegate▲
En C#
delegate
void
MethodeDelegate
(
int
i);
En Delphi .NET
MethodeDelegate = function
(x: Integer
): string
of
object
;
IX-E-2-b. Gestionnaire d'événement▲
En C#
public
delegate
void
EventHandler
(
Object sender,
EventArgs e);
En Delphi .NET
TEventHandler = Procedure
(Sender:TObject ; e : EventArgs) Of
Object
;
La composition de délégué en C# se fait avec les opérateurs suivants += et -=
La composition de délégué Delphi .NET se fait de la manière suivante :
TCompte=Class
...
// Utilisation d'une propriété dans une classe
Property
MonDelegue:TMonDelegue add FMonDelegue remove FMonDelegue;
...
end
;
...
// L'ajout d'un délégué
Include(UnCompte.MonDelegue,@Traite);
...
// La suppression d'un délégué
Exclude(UnCompte.MonDelegue,@Traite);
...
IX-F. Passage de paramètres▲
C# |
Delphi .NET |
Commentaire |
---|---|---|
int a |
a:integer |
Passage par valeur |
ref |
Var |
C# : Toute modification apportée au paramètre dans la méthode est reflétée dans cette variable lorsque la méthode appelante récupère le contrôle. |
const |
Const |
|
out |
Out |
C# : Toute modification apportée au paramètre dans la méthode est reflétée dans cette variable lorsque la méthode appelante récupère le contrôle. |
Valeur par défaut |
identifiant=valeur |
C# : TODO |
Voir aussi:
Passage de paramètres en C#
IX-G. Paramètres en nombre variable▲
Sous C# un tableau de paramètres est déclaré avec un modificateur params. Il ne peut exister qu'un tableau de paramètres pour une méthode donnée, et celui-ci doit être le dernier paramètre spécifié. Le type d'un tableau de paramètres est toujours un type tableau unidimensionnel.
public
class
Console
{
public
static
void
Write
(
string
fmt,
params
object
[]
args) {...}
public
static
void
WriteLine
(
string
fmt,
params
object
[]
args) {...}
...
}
Sous Delphi .Net ce type ne nécessite pas l'utilisation d'un mot clé, on le déclare par un paramètre tableau ouvert contenant des TObjet.
Procedure
(fmt: string
; Args : array
of
TObject);
Vous pouvez consulter la FAQ Delphi .NET : Comment passer un nombre variable de paramètres à une procédure ?
X. Propriétés▲
Les modificateurs autorisés sont new, static, virtual, abstract, override et une combinaison valide des quatre modificateurs d'accès (public…).
using
System;
class
Person
{
private
int
myAge =
0
;
// Déclare une propriété Age de type integer:
public
int
Age
{
// Déclare les méthodes accesseur.
get
{
return
myAge;
}
set
{
myAge =
value
;
}
}
}
En C# la déclaration de méthodes accesseurs (Set et Get) est obligatoire. La variable value est ajoutée dans ce cas par le compilateur.
En Delphi .NET elles sont créées par le compilateur si on référence directement une variable.
Propriété en read-only :
// Area est une propriété en read-only.
public
abstract
double
Area
{
get
;
}
Surcharge de propriété :
// Redéclaration de la propriété Area dans une classe dérivée
public
override
double
Area
{
get
{
return
mySide *
mySide;
}
}
Sous Delphi pour .NET seules sont supportées les propriétés de type suivant :
- Simple ;
- Énuméré ;
- Ensemble ;
- Objet ;
- Tableau.
Déclarer une valeur par défaut pour une propriété n'a pas pour effet de définir cette propriété par cette valeur.
X-A. Comparaison entre les propriétés et les indexeurs▲
TODO : comparaison
Les indexeurs sont similaires aux propriétés. À l'exception des différences répertoriées dans le tableau ci-dessous, toutes les règles définies pour les accesseurs des propriétés s'appliquent aux accesseurs des indexeurs.
Propriété |
Indexeur |
Delphi .Net |
---|---|---|
Identifiée par son nom. |
Identifié par sa signature. |
|
Accès par le biais d'un nom simple ou de l'accès à un membre. |
Accès par le biais de l'accès à un élément. |
|
Peut être un membre statique ou un membre d'instance. |
Doit être un membre d'instance. |
|
Un accesseur get d'une propriété n'a aucun paramètre. |
Un accesseur get d'un indexeur possède la même liste de paramètres formels que l'indexeur. |
|
Un accesseur set d'une propriété contient le paramètre value implicite. |
Un accesseur set d'un indexeur possède la même liste de paramètres formels que l'indexeur, outre le paramètre value. |
XI. Structure de données▲
XI-A. Struct▲
public
struct
Point
{
public
int
x,
y;
public
Point
(
int
p1,
int
p2)
{
x =
p1;
y =
p2;
}
}
La construction d'une structure (struct en C#) se fait en 2 étapes sous Delphi .Net.
La première dans la partie Interface.
Type
Point = Record
x, y : integer
;
constructor
Point.Create(p1,p2 : integer
) ;
end
;
et la seconde dans la partie implementation.
constructor
Point.Create(p1,p2 : integer
) ;
begin
x:=p1;
y:=p2;
end
;
end
;
XI-B. Tableau▲
Les tableaux sont des objets et peuvent être de type unidimensionnel, multidimensionnel et des tableaux de tableaux (jagged array).
int
[]
arr =
new
int
[
5
];
arr[
0
]
=
2
;
var
arr : array
[0
..4
] of
integer
; // tableau statique
begin
arr[0
]:= 2
;
Utilisation d'un initialiseur de tableau
int
[]
arr =
new
int
[
3
]
{
0
,
1
,
2
};
arr:= New(array
[] of
integer
,(0
,1
,2
)); ...
XI-B-1. Tableau de tableaux (jagged array)▲
// tableau de tableaux (jagged array)
byte
[][]
scores =
new
byte
[
5
][];
// Création du "jagged array"
for
(
int
i =
0
;
i <
scores.
Length;
i++
)
{
scores[
i]
=
new
byte
[
i+
3
];
}
type
TScores = Array
of
Array
of
byte
; // Tableaux dynamiques multidimensionnels
var
Scores :TScores;
i: integer
;
begin
SetLength(Scores,10
); // Allocation des lignes
// Création du "jagged array"
for
i := Low(Scores) to
High(Scores) do
SetLength(cores[i], i+3
); // Allocation des colonnes
Le terme jagged peut être traduit par déchiquetée, mais irrégulier semble plus approprié. Jag voulant signifier déchiré (saoul) :*)
XII. Déclaration de variables▲
Les variables en C# se déclarent tout de suite après la déclaration du nom de classe.
class
ExempleVisible2 {
int
a =
10
;
// Cette initialisation est déclarée dans le constructeur.
int
g (
int
x )
{
return
3
*
x-
a;
}
ExempleVisible2=Class
public
a : integer
;
Function
g(x : integer
):Integer
;
Constructor
Create;
end
;
// L'assignation de a = 10 du C# est à la charge du développeur en Delphi .NET.
Constructor
Create;
begin
a:=10
;
end
;
En C# on peut aussi déclarer des variables 'à la volée' directement le code, mais cette possibilité n'est pas supportée sous Delphi pour .NET, ce langage restant déclaratif.
// Extrait de l'unité System.pas
...
var
LMainThread: System.Threading.Thread;
function
MainThread: System.Threading.Thread;
begin
Result := LMainThread;
end
;
var
LastRandSeed: Integer
= -1
;
RandomEngine: System.Random;
procedure
InitRandom;
begin
...
XIII. Instructions diverses▲
C# |
Delphi .NET |
Commentaire |
---|---|---|
using |
uses |
Import de types définis dans d'autres espaces de noms, dans ce contexte le mot clé using est converti en uses . |
Alias using |
NI. |
C# : Créer un alias pour un espace de noms (un alias using). |
fixed |
GCHandle |
C# : |
lock() |
Monitor |
C# : lock(directory) {…} |
// |
// |
La déclaration des commentaires est identique pour // et /* */. |
P.x = P.y= 10; |
P.x:=10; |
Assignation multiple. |
123.ToString |
Integer(123).ToString |
Delphi .Net : L'utilisation de méthode sur des types primitifs nécessite un transtypage. |
Notez la seconde possibilité d'utilisation du mot clé using en C#:
L'instruction using définit une portée au bout de laquelle un objet est supprimé.
using
(
Object MonObjet=
new
Object)
{
MonObjet.
FaitqqChose;
}
En Delphi .Net ce mot clé peut être remplacé par la construction With do suivante :
with
MonObjet.Create do
try
MonObjet.FaitqqChose;
finally
if
Assigned(MonObjet) then
(MonObjet as
IDisposable).Dispose;
end
;
L'objet que vous instanciez doit implémenter l'interface System.IDisposable.
XIII-A. Utilisation de mot clé réservé▲
public
FileInfo lockFileInfo;
public
override
bool
Obtain
(
)
{
try
{
FileStream fs =
lockFileInfo.
Create
(
);
fs.
Close
(
);
}
catch
{
return
false
;
}
return
true
;
}
var
fs: FileStream;
begin
try
fs := lockFileInfo.Create(''
);
Provoque l'erreur :
[Erreur] Project1.dpr(18): E2382 Impossible d'appeler des constructeurs utilisant des variables d'instance
Le mot Create étant un mot clé réservé sous Delphi pour créer une nouvelle instance. Dans ce cas il faut utiliser le caractère éperluet &.
var
fs: FileStream;
lockFileInfo: FileInfo;
Begin
try
lockFileInfo := FileInfo.Create('MyFile.txt'
);
fs := lockFileInfo.&Create;
except
fs.Close();
end
;
XIV. Attributs▲
Les attributs sont identiques aux deux langages. Seule leur déclaration, cf. classe, diffère.
En C# la convention veut que l'on suffixe, lors de la déclaration, le nom de la classe avec Attribut, mais pas dans l'utilisation (le compilateur C# se chargeant d'ajouter le suffixe).
Certains attributs, par exemple conditionnal, sont spécifiques au compilateur C# de Microsoft.
XV. C# 2.0 et les génériques…▲
C#, les possibles évolutions
Extrait d'un interview de Danny Thorpe au sujet de Delphi 2005 :
Microsoft has .NET 2.0 announced for the next year. When can we expect Delphi 10 and what have you planned for it ?
Probably the biggest item in terms of the compiler/language is implementing parameterized type syntax (generic types) in Delphi. We've had parameterized type syntax sketched out on the whiteboards here for ages but other stuff (platforms) kept taking priority. The general goal is to have a product release in 2005, shortly after .NET 2.0 is finalized and released.
C# 3.0 (Comega) la fusion de la POO du SQL et de XML ?
Exemple :
{
Database db =
new
Database
(
"db://amazon.com"
);
XML list =
db.
Search
(
"Author like 'Hugh Darwen'"
);
foreach
(
XML book in
list) {
wishlist.
Add
(
book.
Title +
", "
+
book.
ISBN);
}