Mr Josselin A - C#(.NET)









Délégués

Références

L'actualité

Librairie

L'information

Introduction

C# étant typé statiquement au moment de la compilation, une fois qu'une variable est déclarée elle ne peut plus être redéclarée et aucune valeur d'un autre type ne peut lui être assignée, sauf si ce type peut être converti de manière implicite au type de la variable. Par exemple, string ne peut pas être converti implicitement en int. Après avoir déclaré i comme int, vous ne pouvez donc pas lui assigner la chaîne "Hello", comme l'illustre le code suivant :

Cependant, vous pouvez être amené à copier une valeur dans un paramètre de variable ou de méthode d'un autre type. C'est notamment le cas si vous avez une variable de type entier que vous devez passer à une méthode dont le paramètre est de type double. Il peut également arriver que vous deviez assigner une variable de classe à une variable de type interface. Les opérations de ce genre sont appelées "conversions de types". En C#, vous pouvez effectuer les conversions suivantes :

Conversions implicites : aucune syntaxe spéciale n'est requise, car la conversion est de type sécurisé et les données ne sont pas perdues. Citons par exemple les conversions de types intégraux en d'autres plus importants, et les conversions de classes dérivées en classes de base.

Conversions explicites (casts) : les conversions explicites nécessitent un opérateur de cast. Un cast est exigé quand les informations peuvent être perdues durant la conversion, ou quand la conversion peut échouer pour d'autres raisons. Exemples classiques : conversion numérique en type qui a moins de précision ou une plus petite plage, et conversion d'une instance de classe de base en classe dérivée.

Conversions définies par l'utilisateur : les conversions définies par l'utilisateur sont effectuées par des méthodes spéciales que vous pouvez définir pour permettre des conversions explicites ou implicites entre des types personnalisés qui n'ont pas de relation classe de base/classe dérivée.

Conversions avec les classes d'assistance : pour effectuer une conversion entre des types non compatibles, tels que des entiers et des objets System.DateTime ou des chaînes hexadécimales et des tableaux d'octets, vous pouvez utiliser la classe System.BitConverter, la classe System.Convert et les méthodes Parse des types numériques intégrés, comme Int32.Parse.

Conversions implicites

Pour les types numériques intégrés, une conversion implicite peut être effectuée quand la valeur à stocker peut tenir dans la variable sans être tronquée ni arrondie. Par exemple, une variable de type long (entier sur 64 bits) peut stocker n'importe quelle valeur pouvant être stockée par un int (entier sur 32 bits). Dans l'exemple suivant, le compilateur convertit implicitement la valeur de num à droite en type long avant de l'assigner à bigNum.

Pour les types référence, il existe toujours une conversion implicite entre une classe et l'une de ses interfaces ou classes de base directes ou indirectes. Aucune syntaxe spéciale n'est nécessaire, car une classe dérivée contient toujours tous les membres d'une classe de base.

Conversions explicites

Toutefois, si une conversion ne peut pas être réalisée sans risque de perte d'informations, le compilateur exige une conversion explicite, aussi appelée cast. Un cast est une façon d'informer explicitement le compilateur que vous prévoyez de faire la conversion et que vous savez qu'une perte de données peut se produire. Pour effectuer un cast, spécifiez le type voulu entre parenthèses devant la valeur ou la variable à convertir. Le programme suivant effectue un cast d'un double en int. Le programme ne se compile pas sans le cast.

Pour les types référence, un cast explicite est exigé si vous devez effectuer une conversion d'un type de base en type dérivé :

Une opération cast entre types référence ne change pas le type au moment de l'exécution de l'objet sous-jacent. Elle change seulement le type de la valeur utilisée comme référence à cet objet.

Exceptions de conversion de type au moment de l'exécution

Dans certaines conversions de types référence, le compilateur ne peut pas déterminer si un cast sera valide. Il est possible qu'une opération cast dont la compilation fonctionne échoue au moment de l'exécution. Comme l'illustre l'exemple suivant, un cast de type qui échoue au moment de l'exécution provoque la levée d'une exception InvalidCastException.

C# fournit les opérateurs is et as pour vous permettre de tester la compatibilité avant d'effectuer réellement un cast.

boxing et unboxing

Le boxing est la conversion d'un type valeur en type object ou en un type interface implémenté par ce type valeur. Lorsque le CLR exécute un boxing d'un type valeur, il inclut la valeur dans un wrapper, à l'intérieur d'un System.Object, et la stocke sur le tas managé. L'unboxing extrait le type valeur de l'objet. La conversion boxing est implicite ; la conversion unboxing est explicite. Le concept de boxing et de unboxing repose sur la vue unifiée par C# du système de type, dans lequel une valeur de n'importe quel type peut être traitée en tant qu'objet.

Dans l'exemple suivant, la variable de type entier i est convertie (boxed) et assignée à l'objet o.

L'objet o peut ensuite être unboxed et assigné à la variable de type entier i :

Les exemples suivants montrent comment le boxing est utilisé dans C#.


Performances

Par rapport aux assignations simples, le boxing et l'unboxing sont des processus qui coûtent cher en calcul. Lorsqu'un type valeur est boxed, un nouvel objet doit être alloué et construit. à un degré moindre, le cast requis pour l'unboxing coûte également cher en calcul.

Boxing

Le boxing est utilisé pour stocker des types valeur dans le tas rassemblé par garbage collection. Le boxing est une conversion implicite d'un type valeur en type object ou en un type interface implémenté par ce type valeur. Le boxing d'un type valeur alloue une instance d'objet sur le tas et copie la valeur dans le nouvel objet.

Dans l'exemple suivant, une variable de type valeur est déclarée :

L'instruction ci-dessous réalise implicitement une opération de boxing sur la variable i :

Le résultat de cette instruction crée, sur la pile, un objet o qui fait référence à une valeur de type int sur le tas. Cette valeur est une copie de la valeur de type valeur qui a été assignée à la variable i. La différence entre les deux variables, i et o, est illustrée dans la figure ci-dessous.


Conversion boxing

Il est également possible, mais jamais obligatoire, d'effectuer un boxing explicite comme dans l'exemple suivant :

Description

Cet exemple utilise le boxing pour convertir une variable i (entier) en un objet o. Ensuite, la valeur i stockée dans la variable 123 est remplacée par la valeur 456. L'exemple montre que le type valeur d'origine et que l'objet boxed utilisent des emplacements de mémoire distincts et peuvent, par conséquent, stocker des valeurs différentes.

Exemple


Unboxing

L'unboxing est une conversion explicite du type object en un type valeur, ou d'un type interface en un type valeur qui implémente l'interface. Une opération d'unboxing comprend les étapes suivantes :

  • Vérification de l'instance de l'objet pour s'assurer qu'il s'agit bien d'une valeur boxed du type valeur spécifié.
  • Copie de la valeur de l'instance dans la variable de type valeur.

Les instructions suivantes expliquent les opérations de boxing et d'unboxing :

Le résultat de ces instructions est illustré dans la figure ci-dessous.


Conversion unboxing

Pour que l'unboxing de types valeur réussisse au moment de l'exécution, l'élément qui est unboxed doit être une référence à un objet précédemment créé par boxing d'une instance de ce type valeur. La tentative d'extraction de null provoque un NullReferenceException. La tentative d'extraction d'une référence vers un type de valeur incompatible provoque un InvalidCastException.

Exemple

L'exemple suivant montre un cas d'unboxing non valide et la InvalidCastException qui en résulte. Avec try et catch, un message d'erreur est affiché lorsque l'erreur se produit.

Sortie de ce programme : Specified cast is not valid. Error: Incorrect unboxing.

Si vous modifiez l'instruction :

en :

la conversion sera réalisée, avec le résultat suivant : Unboxing OK.

Type dynamic

C# 4 introduit un nouveau type, appelé dynamic. Il s'agit d'un type statique ; toutefois, un objet de type dynamic ignore la vérification des types statiques. Dans la plupart des cas, il fonctionne comme s'il était de type object. Au moment de la compilation, un élément de type dynamic est supposé prendre en charge n'importe quelle opération. Par conséquent, vous n'avez pas besoin de vous demander si l'objet obtient sa valeur d'une API COM, d'un langage dynamique tel que IronPython, du modèle DOM (Document Object Model) HTML, de la réflexion ou d'une autre partie du programme. Toutefois, si le code n'est pas valide, des erreurs sont détectées au moment de l'exécution.

Par exemple, si la méthode d'instance exampleMethod1 du code suivant ne comporte qu'un seul paramètre, le compilateur reconnaît que le premier appel à la méthode, ec.exampleMethod1(10, 4), n'est pas valide car il contient deux arguments. Cet appel entraîne une erreur du compilateur. Le deuxième appel à la méthode, dynamic_ec.exampleMethod1(10, 4), n'est pas vérifié par le compilateur, car le type de dynamic_ec est dynamic. Par conséquent, aucune erreur de compilateur n'est signalée. Toutefois, l'erreur ne passe pas indéfiniment inaperçue. Elle est détectée au moment de l'exécution et provoque une exception runtime.


Dans ces exemples, le rôle du compilateur consiste à regrouper les informations relatives à l'opération que chaque instruction propose d'exécuter sur l'objet ou l'expression de type dynamic. Au moment de l'exécution, les informations stockées sont examinées, et toute instruction non valide provoque une exception runtime.

Le résultat de la plupart des opérations dynamiques est lui-même de type dynamic. Par exemple, si vous placez le pointeur de la souris sur testSum dans l'exemple suivant, IntelliSense affiche le type (variable locale) dynamic testSum.

Les opérations dans lesquelles le résultat n'est pas dynamic incluent :

  • Les conversions de dynamic vers un autre type.
  • Les appels de constructeur qui incluent des arguments de type dynamic.

Par exemple, le type de testInstance dans la déclaration suivante est ExampleClass, et non pas dynamic :

Conversions

Les conversions entre des objets dynamiques et d'autres types sont faciles à exécuter. Les développeurs peuvent ainsi passer du comportement dynamique au comportement non dynamique, et vice versa.

Tout objet peut être converti implicitement en type dynamique, comme illustré dans les exemples suivants.

Inversement, une conversion implicite peut être appliquée de façon dynamique à toute expression de type dynamic.

Résolution de surcharge avec des arguments de type dynamic

La résolution de surcharge a lieu au moment de l'exécution, et non pas au moment de la compilation, si un ou plusieurs arguments d'un appel de méthode sont de type dynamic, ou si le récepteur de l'appel de méthode est de type dynamic. Dans l'exemple suivant, si la seule méthode exampleMethod2 accessible est définie pour accepter un argument de chaîne, l'envoi de d1 en tant qu'argument n'entraîne pas d'erreur du compilateur, mais provoque une exception runtime. La résolution de surcharge échoue au moment de l'exécution car le type de d1 est int, et exampleMethod2 exige une chaîne.


Dynamic Language Runtime

Le composant Dynamic Language Runtime (DLR) est une nouvelle API de .NET Framework 4. Il fournit l'infrastructure qui prend en charge le type dynamic en C#, ainsi que l'implémentation des langages de programmation dynamique tels que IronPython et IronRuby.

COM interop

C# 4 inclut plusieurs fonctionnalités qui améliorent l'interopérabilité avec les API COM telles que les API Office Automation. L'utilisation du type dynamic et des arguments nommés et facultatifs fait partie des améliorations offertes.

De nombreuses méthodes COM autorisent une variation des types d'arguments et du type de retour en désignant les types comme object. Cela a nécessité un cast explicite des valeurs pour la coordination avec les variables fortement typées en C#. Si vous effectuez la compilation à l'aide de l'option /link (Options du compilateur C#), l'introduction du type dynamic vous permet de traiter les occurrences d'object dans les signatures COM comme si elles étaient de type dynamic, vous évitant ainsi une grande partie des opérations de cast. Par exemple, les instructions suivantes permettent de comparer la façon dont vous accédez à une cellule d'une feuille de calcul Microsoft Office Excel avec le type dynamic et sans le type dynamic.


Convertir un tableau de bytes en int

Cet exemple montre comment utiliser la classe BitConverter pour convertir un tableau d'octets en valeur int, puis la reconvertir en tableau d'octets. Vous devrez peut-être convertir des octets en un type de données intégré après avoir lu les octets sur le réseau. Outre la méthode ToInt32(Bytre[], Int32) de l'exemple, le tableau suivant répertorie les méthodes dans la classe BitConverter qui convertissent des octets (d'un tableau d'octets) en d'autres types intégrés.

Type numérique Méthode
bool ToBoolean(Byte[], Int32)
char ToChar(Byte[], Int32)
double ToDouble(Byte[], Int32)
short ToInt16(Byte[], Int32)
int ToInt32(Byte[], Int32)
long ToInt64(Byte[], Int32)
float ToSingle(Byte[], Int32)
ushort ToUInt16(Byte[], Int32)
uint ToUInt32(Byte[], Int32)
ulong ToUInt64(Byte[], Int32)


Exemple

Cet exemple initialise un tableau d'octets, inverse le tableau si l'architecture de l'ordinateur est little-endian (autrement dit, l'octet le moins significatif est stocké en premier), puis appelle la méthode ToInt32(Byte[], Int32) pour convertir quatre octets du tableau en valeur int. Le deuxième argument de ToInt32(Byte[], Int32) spécifie l'index de départ du tableau d'octets.

La sortie peut varier en fonction du caractère endian de l'architecture de votre ordinateur.


Exemple

Dans cet exemple, la méthode GetBytes(Int32) de la classe BitConverter est appelée pour convertir une valeur int en tableau d'octets.

La sortie peut varier en fonction du caractère endian de l'architecture de votre ordinateur.


Convertir une chaîne en nombre

Vous pouvez convertir une chaîne en nombre en appelant la méthode Parse ou TryParse des différents types numériques (int, long, double, etc.), ou bien en utilisant des méthodes dans la classe System.Convert.

Si vous avez une chaîne, il est légèrement plus efficace et direct d'appeler une méthode TryParse (par exemple int.TryParse("11", out number)) ou une méthode Parse (par exemple, var number = int.Parse("11")). L'utilisation d'une méthode Convert s'avère plus utile pour les objets généraux qui implémentent IConvertible.

Vous pouvez utiliser les méthodes Parse ou TryParse sur le type numérique que doit contenir la chaîne, notamment le type System.Int32. La méthode Convert.ToInt32 utilise Parse en interne. La méthode Parse retourne le nombre converti; la méthode TryParse retourne une valeur Boolean qui indique si la conversion a réussi et retourne le nombre converti dans un outparamètre. Si le format de la chaîne n'est pas valide, Parse lève une exception, tandis que TryParse retourne false. Lorsque vous appelez une méthode Parse, vous devez toujours utiliser la gestion des exceptions pour intercepter une FormatException si l'opération d'analyse échoue.

Appel des méthodes Parse et TryParse

Les méthodes Parse et TryParse ignorent l'espace blanc au début et à la fin de la chaîne, mais tous les autres caractères doivent être des caractères qui forment le type numérique approprié (int, long, ulong, float, decimal, etc.). La présence d'un espace blanc dans la chaîne qui forme le nombre génère une erreur. Par exemple, vous pouvez utiliser decimal.TryParse pour analyser 10, 10.3, 10, mais vous ne pouvez pas utiliser cette méthode pour analyser 10 à partir de 10X, 1 0 (notez l'espace incorporé), 10 .3 (notez l'espace incorporé), 10e1 (float.TryParse fonctionne ici), et ainsi de suite. Par ailleurs, une chaîne dont la valeur est null ou String.Empty ne parvient pas à effectuer une analyse. Vous pouvez rechercher une chaîne Null ou vide avant de tenter de l'analyser en appelant la méthode String.IsNullOrEmpty.

L'exemple suivant illustre des appels à Parse et à TryParse qui ont réussi ou échoué.


L'exemple suivant illustre une approche de l'analyse d'une chaîne prévoyant d'inclure des caractères numériques de début (y compris des caractères hexadécimaux) et des caractères non numériques de fin. Il attribue dès le début des caractères valides à une nouvelle chaîne avant d'appeler la méthode TryParse. étant donné que les chaînes à analyser contiennent un petit nombre de caractères, l'exemple appelle la méthode String.Concat pour attribuer des caractères valides à une nouvelle chaîne. Pour une chaîne plus grande, la classe StringBuilder peut être utilisée à la place.



Appel des méthodes de conversion

Le tableau suivant répertorie quelques unes des méthodes de la classe Convert que vous pouvez utiliser pour convertir une chaîne en nombre.

Type numérique Méthode
decimal ToDecimal(String)
float ToSingle(String)
double ToDouble(String)
short ToInt16(String)
int ToInt32(String)
long ToInt64(String)
ushort ToUInt16(String)
uint ToUInt32(String)
ulong ToUInt64(String)

L'exemple suivant appelle la méthode Convert.ToInt32(String) pour convertir une entrée de type chaîne en int. L'exemple intercepte les deux exceptions les plus communes qui peuvent être levées par cette méthode, FormatException et OverflowException. Si le nombre obtenu peut être incrémenté sans dépasser Int32.MaxValue, l'exemple ajoute 1 au résultat et affiche la sortie.


Conversion entre chaînes hexa et types numériques

Ces exemples montrent comment effectuer les tâches suivantes :

  • Obtenir la valeur hexadécimale de chaque caractère dans une chaîne (string).
  • Obtenir la valeur char qui correspond à chaque valeur d'une chaîne hexadécimale.
  • Convertir une string hexadécimale en int.
  • Convertir une string hexadécimale en float.
  • Convertir un tableau d'octets en string hexadécimale.

Exemple

Cet exemple génère la valeur hexadécimale de chaque caractère dans une string. Il convertit d'abord la string en un tableau de caractères. Ensuite, il appelle ToInt32(Char) sur chaque caractère afin d'obtenir sa valeur numérique. Pour finir, il représente le nombre sous forme hexadécimale dans une string.

Exemple

Cet exemple analyse une string de valeurs hexadécimales et génère le caractère correspondant à chacune d'elles. Il appelle d'abord la méthode Split(Char[]) pour obtenir chaque valeur hexadécimale sous la forme d'une string individuelle dans un tableau. Ensuite, il appelle ToInt32(String, Int32) pour convertir la valeur hexadécimale en valeur décimale représentée sous forme d'objet int. Il illustre deux manières d'obtenir le caractère correspondant à ce code de caractère. La première technique utilise string, qui retourne le caractère correspondant à l'argument entier sous forme de ConvertFromUtf32(Int32). La deuxième technique effectue un cast explicite de int en char.

Exemple

Cet exemple montre une autre façon de convertir un string hexadécimal en entier, en appelant la méthode Parse(String, NumberStyles).

Exemple

L'exemple suivant montre comment convertir un string hexadécimal en float à l'aide de la classe System.BitConverter et de la méthode UInt32.Parse.

Exemple

L'exemple suivant montre comment convertir un tableau de octets en chaîne hexadécimale à l'aide de la classe System.BitConverter.