Types > Types référence

Références

L'actualité

Librairie

L'information

Caractéristiques des types référence

Il existe deux genres de types en C# : les types référence et les types valeur.

Les variables des types référence font référence à leurs données (objets), tandis que les variables des types valeur contiennent directement leurs données.

Avec les types référence, deux variables peuvent faire référence au même objet ; par conséquent, les opérations sur une variable peuvent affecter le même objet référencé par l'autre variable. Avec les types valeur, chaque variable a sa propre copie des données et les opérations sur une variable ne peuvent pas affecter l'autre (sauf pour les variables de paramètre in, ref et out).

Les mots clés suivants sont utilisés pour déclarer des types référence :

  • class
  • interface
  • delegate

C# fournit également les types référence intégrés suivants :

  • dynamic
  • object
  • string

class

Les classes sont déclarées à l'aide du mot clé class, comme l'illustre l'exemple suivant :

Notes

Le langage C# ne permet qu'un seul héritage. Cela signifie qu'une classe peut uniquement hériter de l'implémentation d'une seule classe de base. Toutefois, une classe peut implémenter plusieurs interfaces.

Le tableau suivant répertorie des exemples d'héritage de classe et d'implémentation d'interface :
Héritage Exemple
Aucun class ClassA { }
Single class DerivedClass: BaseClass { }
Aucun, implémente deux interfaces class ImplClass: IFace1, IFace2 { }
Unique, implémente une seule interface class ImplDerivedClass: BaseClass, IFace1 { }
Les classes que vous déclarez directement dans un espace de noms, non imbriquées dans d'autres classes, peuvent être public ou internal. Par défaut, les classes sont internal.

Les membres de classe, notamment les classes imbriquées, peuvent être public, protected internal, protected, internal, private ou private protected. Par défaut, ils sont private.

Exemple
L'exemple suivant explique comment déclarer des champs, des constructeurs et des méthodes de classe. Il illustre également l'instanciation d'un objet et l'impression des données d'une instance. Dans cet exemple, deux classes sont déclarées. La première, Child, contient deux champs privés (name et age), deux constructeurs public et une méthode public. La deuxième, StringTest, contient Main.

Commentaires
Notez que, dans l'exemple précédant, les champs privés (name et age) ne sont accessibles que par le biais de la méthode publique de la classe Child. Par exemple, vous ne pouvez pas imprimer le name de Child à partir de la méthode Main en utilisant une instruction comme celle-ci :

L'accès aux membres private de Child à partir de Main est uniquement possible si Main est un membre de la classe.

Du fait que les types déclarés dans une classe sans modificateur d'accès sont par défaut private, les données membres dans cet exemple sont toujours private si le mot clé est supprimé.

Notez enfin que pour l'objet créé à l'aide du constructeur par défaut (child3), le champ age est initialisé par défaut à la valeur zéro.


delegate

La déclaration d'un type delegate est semblable à une signature de méthode. Elle a une valeur de retour et un nombre quelconque de paramètres de type quelconque :

Un delegate est un type référence qui peut être utilisé pour encapsuler une méthode anonyme ou nommée.

Notes
Les delegate sont la base des événements. Un delegate peut être instancié en l'associant à une méthode nommée ou anonyme.

Le delegate doit être instancié avec une méthode ou une expression lambda qui a un type de retour compatible et des paramètres d'entrée. Pour une utilisation avec des méthodes anonymes, le délégué et le code à lui associer sont déclarés ensemble. Les deux façons d'instancier un delegate sont décrites dans cette section.


dynamic

Le type dynamic permet aux opérations dans lesquelles il se produit de contourner la vérification de type au moment de la compilation. Au lieu de cela, ces opérations sont résolues au moment de l'exécution. Le type dynamic simplifie l'accès aux API COM telles que les API Office Automation, et également aux API dynamiques telles que les bibliothèques IronPython et au modèle DOM (Document Object Model) HTML.

Le type dynamic se comporte comme le type object dans la plupart des cas. Toutefois, les opérations qui contiennent des expressions de type dynamic ne sont pas résolues et leur type n'est pas vérifié par le compilateur. Le compilateur empaquète des informations sur l'opération, qui sont ensuite utilisées pour évaluer l'opération au moment de l'exécution. Dans le cadre du processus, les variables de type dynamic sont compilées dans des variables de type object. Ainsi, le type dynamic existe seulement au moment de la compilation, et non au moment de l'exécution.

L'exemple suivant compare une variable de type dynamic à une variable de type object. Pour vérifier le type de chaque variable au moment de la compilation, placez le pointeur de la souris sur dyn ou obj dans les instructions WriteLine. IntelliSense affiche dynamic pour dyn et object pour obj.

Les instructions WriteLine affichent les types d'exécution de dyn et obj. À ce stade, tous deux ont le même type, entier. La sortie suivante est produite :

System.Int32
System.Int32

Pour voir la différence entre dyn et obj au moment de la compilation, ajoutez les deux lignes suivantes entre les déclarations et les instructions WriteLine de l'exemple précédent.

Une erreur du compilateur est signalée pour la tentative d'ajout d'un entier et un d'objet dans l'expression obj + 3. Toutefois, aucune erreur n'est signalée pour dyn + 3. L'expression qui contient dyn n'est pas vérifié au moment de la compilation, car le type de dyn est dynamic.

Contexte

Le mot clé dynamic peut apparaître directement ou en tant que composant d'un type construit dans les situations suivantes :

Dans les déclarations, comme le type d'une propriété, d'un champ, d'un indexeur, d'un paramètre, d'une valeur de retour, d'une variable locale ou d'une contrainte de type. La définition de classe suivante utilise dynamic dans plusieurs déclarations différentes.

Dans les conversions de type explicites, comme le type cible d'une conversion.

Dans tout contexte où les types servent de valeurs, comme sur le côté droit d'un opérateur is ou d'un opérateur as, ou comme argument de typeof dans le cadre d'un type construit. Par exemple, dynamic peut être utilisé dans les expressions suivantes.

Exemple

L'exemple suivant utilise dynamic dans plusieurs déclarations. La méthode Main compare également la vérification de type au moment de la compilation avec la vérification de type au moment de l'exécution.

interface

Une interface contient uniquement des signatures de méthodes, de propriétés, d'événements ou d'indexeurs. Une class ou un struct qui implémente l'interface doit implémenter les membres de l'interface qui sont spécifiés dans la définition de l'interface. Dans l'exemple suivant, la class ImplementationClass doit implémenter une méthode nommée SampleMethod qui n'a aucun paramètre et qui retourne void.

Une interface peut être membre d'un espace de noms ou d'une classe, et peut contenir les signatures des membres suivants:

  • Méthodes
  • Propriétés
  • Indexeurs
  • événements

Une interface peut hériter d'une ou de plusieurs interfaces de base. Lorsqu'une liste de types de base contient une classe de base et des interfaces, la classe de base doit figurer en premier dans la liste.

Une classe qui implémente une interface peut implémenter explicitement les membres de cette interface. Un membre implémenté explicitement n'est pas accessible via une instance de classe, mais uniquement via une instance de l'interface.

Exemple
L'exemple suivant montre une implémentation d'interface. Dans cet exemple, l'interface contient la déclaration de propriété, et la classe contient l'implémentation. Toutes les instances d'une classe qui implémentent IPoint ont les propriétés entières x et y.


object

Le type object est un alias de Object dans .NET. Dans le système de type unifié de C#, tous les types (les types référence et valeur, prédéfinis ou définis par l'utilisateur) héritent directement ou indirectement du type Object. Vous pouvez assigner des valeurs de tout type aux variables de type object. Quand une variable d'un type valeur est convertie en type objet, elle est dite boxed. Quand une variable de type objet est convertie en type valeur, elle est dite unboxed.

Exemple
L'exemple suivant montre comment les variables de type object acceptent des valeurs de tout type de données et comment les variables de type object utilisent des méthodes d'Object du .NET Framework.

string

Le type string représente une séquence de zéro, un ou plusieurs caractères Unicode. string est un alias de String dans .NET.

Bien que string soit un type référence, les opérateurs d'égalité (== et != ) sont définis pour comparer les valeurs d'objets string, pas les références. Cela permet de tester l'égalité de chaînes de façon plus intuitive. Par exemple :

Cette opération affiche "True", puis "False", car le contenu des chaînes est équivalent, mais a et b ne font pas référence à la même instance de chaîne.

L'opérateur + concatène les chaînes :

Cela crée un objet String qui contient good morning.

Les chaînes sont immuables : il est impossible de changer le contenu d'un objet String après avoir créé l'objet, bien que la syntaxe semble indiquer le contraire. Par exemple, lorsque vous écrivez ce code, le compilateur crée en fait un nouvel objet String pour stocker la nouvelle séquence de caractères, et ce nouvel objet est assigné à b. La chaîne h est alors disponible pour le garbage collector.

L'opérateur [] peut être utilisé pour un accès en lecture seule aux différents caractères d'un objet string :

De la même façon, l'opérateur [] permet également d'itérer sur chaque caractère dans un string :

Les littéraux de chaîne sont de type string et peuvent être écrits sous deux formes, entre guillemets et @-quoted. Les littéraux de chaîne entre guillemets sont placés entre guillemets doubles (") :

Les littéraux de chaîne peuvent contenir tout littéral de caractère. Les séquences d'échappement sont incluses. L'exemple suivant utilise la séquence d'échappement \\ pour la barre oblique inverse, \u0066 pour la lettre f et \n pour un saut de ligne.

Le code d'échappement \udddd (où dddd est un nombre à quatre chiffres) représente le caractère Unicode U+dddd. Les codes d'échappement Unicode à huit chiffres sont également reconnus : \Udddddddd.

Les littéraux de chaîne textuelle commencent par @ et sont placés entre guillemets doubles. Par exemple :

L'avantage des chaînes textuelles est que les séquences d'échappement ne sont pas traitées, ce qui facilite l'écriture, par exemple, d'un nom de fichier complet :

Pour inclure un guillemet double dans une chaîne @-quoted, doublez-le :

Exemple