Cast et conversions de types (guide de programmation C#)

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 :

int i;

// error CS0029: can't implicitly convert type 'string' to 'int'
i = "Hello";

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 aboutit toujours et aucune donnée n’est perdue. 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 une expression 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 utilisent 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. Pour plus d’informations, consultez Opérateurs de conversion définie par l’utilisateur.

  • 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. Pour plus d’informations, consultez Guide pratique pour convertir un tableau d’octets en int, Guide pratique pour convertir une chaîne en nombre et Guide pratique pour effectuer une conversion entre des chaînes hexadécimales et des types numériques.

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. Pour les types intégraux, cela signifie que la plage du type de source est un sous-ensemble approprié de la plage du type cible. 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.

// Implicit conversion. A long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;

Pour obtenir la liste complète de toutes les conversions numériques implicites, consultez la section Conversions numériques implicites de l’article Conversions numériques intégrées.

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.

Derived d = new Derived();

// Always OK.
Base b = d;

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 un moyen d’informer explicitement le compilateur que vous prévoyez d’effectuer la conversion et que vous êtes conscient que des pertes de données peuvent se produire, ou que le cast peut échouer au moment de l’exécution. 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.

class Test
{
    static void Main()
    {
        double x = 1234.7;
        int a;
        // Cast double to int.
        a = (int)x;
        System.Console.WriteLine(a);
    }
}
// Output: 1234

Pour obtenir la liste des conversions numériques explicites prises en charge, consultez la section Conversions numériques explicites de l’article Conversions numériques intégrées.

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é :

// Create a new derived type.
Giraffe g = new Giraffe();

// Implicit conversion to base type is safe.
Animal a = g;

// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe)a;

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. Pour plus d’informations, consultez Polymorphisme.

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.

class Animal
{
    public void Eat() => System.Console.WriteLine("Eating.");

    public override string ToString() => "I am an animal.";
}

class Reptile : Animal { }
class Mammal : Animal { }

class UnSafeCast
{
    static void Main()
    {
        Test(new Mammal());

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    static void Test(Animal a)
    {
        // System.InvalidCastException at run time
        // Unable to cast object of type 'Mammal' to type 'Reptile'
        Reptile r = (Reptile)a;
    }
}

La méthode Test possède un paramètre Animal, et le fait de transformer explicitement l’argument a en Reptile constitue une hypothèse dangereuse. Il est préférable de vérifier le type avant de faire des hypothèses. C# fournit l’opérateur is pour vous permettre de tester la compatibilité avant d’effectuer réellement un cast. Pour plus d’informations, consultez Guide pratique pour caster de manière sécurisée avec les critères spéciaux, ainsi que les opérateurs is et as.

spécification du langage C#

Pour plus d’informations, consultez la section Conversions de la spécification du langage C#.

Voir aussi