Ci-dessous est un détachement de l' article suivant:
La différence entre la contrainte et le casting est souvent négligé. Je peux voir pourquoi; de nombreuses langues ont le même (ou similaire) de la syntaxe et de la terminologie pour les deux opérations. Certaines langues peuvent même se référer à la conversion comme "casting", mais l'explication suivante fait référence à des notions dans le CTS.
Si vous essayez d'attribuer une valeur d'un type à l'emplacement d'un type différent, vous pouvez générer une valeur de type nouveau qui a un sens similaire à l'original. C'est la contrainte. La contrainte permet d'utiliser le nouveau type par la création d'une nouvelle valeur, qui ressemble à l'original. Certaines contraintes peuvent disposer de données (par exemple, la conversion de l'int 0x12345678 à court 0x5678), tandis que d'autres ne peuvent pas (par exemple, la conversion de l'int 0x00000008 à court 0x0008, ou le long 0x0000000000000008).
Rappelons que les valeurs peuvent avoir plusieurs types. Si votre situation est un peu différente, et que vous ne souhaitez sélectionner un autre de la valeur de types, le casting est l'outil pour le travail. Casting indique simplement que vous souhaitez utiliser sur un type qui a de la valeur.
La différence au niveau du code varie de C# à l'IL. En C#, à la fois de la coulée et de la coercition look assez similaire:
static void ChangeTypes(int number, System.IO.Stream stream)
{
long longNumber = number;
short shortNumber = (short)number;
IDisposable disposableStream = stream;
System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}
Au niveau IL, ils sont très différents:
ldarg.0
conv.i8
stloc.0
ldarg.0
conv.i2
stloc.1
ldarg.1
stloc.2
ldarg.1
castclass [mscorlib]System.IO.FileStream
stloc.3
Comme pour le niveau logique, il y a quelques différences importantes. Ce qui est le plus important à retenir est que la contrainte crée une nouvelle valeur, tandis que le casting n'est pas. L'identité de la valeur initiale et la valeur après la coulée sont les mêmes, alors que l'identité d'une contrainte valeur diffère de la valeur d'origine; encore de la contrainte crée une nouvelle, distincte exemple, alors que le casting n'est pas. Un corollaire est que le résultat du casting et de l'original sera toujours équivalent (à la fois de l'identité et de l'égalité), mais une contrainte de valeur peut ou peut ne pas être égale à l'original, et ne partage jamais l'identité d'origine.
Il est facile de voir les implications de la contrainte dans les exemples ci-dessus, comme les types numériques sont toujours copiés par valeur. Les choses deviennent un peu plus compliqué lorsque vous travaillez avec des types référence.
class Name : Tuple<string, string>
{
public Name(string first, string last)
: base(first, last)
{
}
public static implicit operator string[](Name name)
{
return new string[] { name.Item1, name.Item2 };
}
}
Dans l'exemple ci-dessous, une conversion est une fonte, tandis que l'autre est une contrainte.
Tuple<string, string> tuple = name;
string[] strings = name;
Après ces conversions, tuple et le nom de l'égalité, mais les cordes n'est pas égal à l'un d'eux. Vous pourrait rendre la situation un peu mieux (ou un peu plus de confusion) par la mise en œuvre de Equals() et operator ==() sur le Nom de la catégorie à comparer d'un Nom et d'un string[]. Ces opérateurs sont à "corriger" la comparaison de problème, mais vous auriez encore deux instances séparées; toute modification des chaînes ne seraient pas reflétés dans le nom ou le n-uplet, tandis que les changements apportés à l'un des nom ou le n-uplet serait le reflet de nom et de tuple, mais pas dans les cordes.
Bien que l'exemple ci-dessus était destiné à illustrer certaines différences entre la coulée et de la coercition, il sert également comme un excellent exemple de pourquoi vous devriez être très prudent sur l'utilisation d'opérateurs de conversion avec les types de référence en C#.