Le cast et la conversion de type sont deux façons différentes de faire passer une expression d'un type de données à un autre.
La documentation C# classe la conversion de type comme l'utilisation de l'opérateur as ou de l'opérateur is. Le cast est défini comme l'utilisation de l'opérateur de cast.
En C#, très souvent, en dehors du domaine des valeurs numériques et des hiérarchies de classes, il te faudra effectuer une conversion en appelant un membre du type cible, comme Int32.Parse() qui convertit une string en entier, ou en appelant un membre du type source, par exemple object.ToString(). Les développeurs Javascript et d'autres langages dynamiques doivent en être conscients.
Note que des opérateurs de cast implicite et explicite (abordés dans operator-overloading) sont disponibles, et qu'ils permettent d'apporter un cast assez arbitraire à tes propres types.
Le système de types de C# est un peu plus strict que celui de C ou de Javascript, et par conséquent, les opérations de cast sont plus limitées. Le cast implicite a lieu entre deux types numériques tant que le type cible peut préserver l'ordre de grandeur et le signe de la valeur du type source. Remarque dans la documentation l'exception concernant la conversion vers des nombres réels, où la précision peut être perdue.
Un cast implicite n'est signalé par aucune syntaxe particulière. Par exemple :
int myInt = 1729;
long myLong = myInt;
Il n'existe aucune conversion implicite d'une expression numérique (ou string) en bool. La Base Class Library (BCL) fournit Convert.ToBoolean() à cet effet.
Une expression de type char peut être convertie implicitement en int. Le cast dans l'autre sens doit être explicite. Toutes les valeurs de int ne sont pas des caractères utf 16 valides.
Lorsqu'un type numérique ne peut pas être converti implicitement, on peut généralement utiliser l'opérateur de cast explicite.
Lorsque la valeur convertie ne peut pas être représentée par le type cible, parce qu'il n'est pas assez large ou qu'il y a un conflit de signe, une exception de dépassement de capacité peut être levée dans le cas des entiers, ou la variable du type cible peut prendre la valeur Infinity dans le cas des float et des double.
Une expression de type int peut être convertie explicitement en char. Cela peut produire un char non valide.
int largeInt = Int32.MaxValue;
int largeNegInt = Int32.MinValue;
ushort shortUnsignedInt = ushort.MaxValue;
float largeFloat = float.MaxValue;
float smallFloat = 17.29f;
// implicit cast
int from_ushort = shortUnsignedInt; // 65535
float from_int = largeInt; // -21474836E+09
int from_char = 'a'; // 96
// explicit cast
uint from_largeInt = (uint)largeInt; // 2147483647
uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked)
int from_smallFloat = (int) smallFloat; // 17
int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked)
char from_intc = (char) 32; // ' '
char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown
// no cast available
int fromString = Int32.Parse("42"); // 42
string toString = largeInt.ToString(); // "2147483647"
int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown
Voir cet article pour le mot-clé checked.
Tout type peut être converti implicitement en sa classe de base ou son interface.
IList<int> ll = new List<int>();
On peut utiliser un opérateur de cast pour convertir une classe de base en classe dérivée.
IList<int> ll = new List<int>();
List<int> l = (List<int>)ll;
Si le cast échoue parce que le type de l'expression convertie n'est pas lié au type vers lequel elle est convertie, une instance de InvalidCastException est levée.
Une approche plus courante pour ces conversions de type consiste à utiliser le mot-clé is :
interface IFoo { int Bar(); }
class Foo : IFoo { public int Bar() { return 42; }}
Object r = new Random();
IFoo ifoo = new Foo();
Object o = new Foo();
int result = 1729;
if (ifoo is Foo foo)
{
result = foo.Bar();
}
// result == 42
result = 1729;
if (o is Foo foo2)
{
result = foo2.Bar();
}
// result == 42
result = 1729;
if (r is Foo foo3)
{
result = foo3.Bar();
}
// result == 1729
Le mot-clé as remplit une fonction similaire à is, par exemple var foo = ifoo as Foo;. Dans cet exemple, foo vaudra null si ifoo n'est pas de type Foo, sinon ifoo lui sera affecté.
Les types peuvent définir leurs propres opérateurs de cast explicites et implicites personnalisés.
Dans la BCL, les conversions entre la structure BigInteger et d'autres types numériques sont des exemples de casts explicites et implicites.
typeof
Si tu as besoin de déterminer le type précis d'un objet, is peut être un peu trop permissif, car il convertit un objet en une classe ou en l'une de ses classes de base. Dans ce cas, typeof et Object.GetType() sont la solution.
object o = new List<int>();
o is ICollection<int> // true
o.GetType() == typeof(ICollection<int>) // false
o is List<int> // true
o.GetType() == typeof(List<int>) // true