Quelle est la différence entre le casting et la coercition?

J’ai vu les deux termes être utilisés de manière presque interchangeable dans diverses explications en ligne, et la plupart des manuels que j’ai consultés ne sont pas non plus tout à fait clairs sur la distinction.

Y a-t-il peut-être un moyen simple et clair d’expliquer la différence que vous connaissez?

Type conversion (parfois aussi appelé type cast )

Utiliser une valeur d’un type dans un contexte qui en attend un autre.

Type de conversion non converti (parfois appelé type pun )

Un changement qui ne modifie pas les bits sous-jacents.

Coercition

Processus par lequel un compilateur convertit automatiquement une valeur d’un type en une valeur d’un autre type lorsque ce second type est requirejs par le contexte environnant.

Type Conversion :

La conversion de mots se réfère à la modification implicite ou explicite d’une valeur d’un type de données à un autre, par exemple un entier de 16 bits à un entier de 32 bits.

Le mot coercition est utilisé pour désigner une conversion implicite.

Le mot cast fait généralement référence à une conversion de type explicite (par opposition à une conversion implicite), qu’il s’agisse d’une réinterprétation d’un modèle de bit ou d’une conversion réelle.

Ainsi, la coercition est implicite, la dissortingbution est explicite et la conversion en est une.


Quelques exemples (de la même source ):

Coercition (implicite):

double d; int i; if (d > i) d = i; 

Cast (explicite):

 double da = 3.3; double db = 3.3; double dc = 3.4; int result = (int)da + (int)db + (int)dc; //result == 9 

Les utilisations varient, comme vous le constatez.

Mes usages personnels sont:

  • Une “dissortingbution” est l’utilisation d’un opérateur de dissortingbution . Un opérateur de dissortingbution indique au compilateur que (1) cette expression n’est pas connue pour être du type donné, mais je vous promets que la valeur sera de ce type à l’exécution; le compilateur doit traiter l’expression comme étant du type donné et le moteur d’exécution génère une erreur s’il ne l’est pas, ou (2) l’expression est entièrement différente, mais il existe un moyen bien connu d’associer des instances du type de l’expression avec des instances du type cast-to. Le compilateur est chargé de générer du code qui effectue la conversion. Le lecteur attentif notera que ce sont des opposés, ce qui, à mon avis, est une astuce.

  • Une “conversion” est une opération par laquelle une valeur d’un type est traitée comme une valeur d’un autre type – généralement un type différent, bien qu’une “conversion d’identité” soit toujours une conversion, techniquement parlant. La conversion peut être “modification de la représentation”, comme int pour doubler, ou “représentation préservée” comme chaîne à object. Les conversions peuvent être “implicites”, ne nécessitant pas de transtypage, ou “explicites”, qui nécessitent une dissortingbution.

  • Une “coercition” est une conversion implicite de changement de représentation.

Le moulage est le processus par lequel vous traitez un type d’object comme un autre type, le Coercing convertit un object en un autre.

Notez que dans l’ancien processus, il n’y a pas de conversion impliquée, vous avez un type que vous souhaitez traiter comme un autre, par exemple, vous avez 3 objects différents qui héritent d’un type de base, et vous avez une méthode qui prendra cela. type de base, à tout moment, si vous avez maintenant le type enfant spécifique, vous pouvez le convertir à ce qu’il est et utiliser toutes les méthodes et propriétés spécifiques de cet object et ne pas créer une nouvelle instance de l’object.

D’autre part, la coercition implique la création d’un nouvel object en mémoire du nouveau type, puis le type original serait copié sur le nouveau, laissant les deux objects en mémoire (jusqu’à ce que les récupérateurs de mémoire soient supprimés ou les deux). .

Voici un article de l’ article suivant :

La différence entre la coercition et le casting est souvent négligée. Je peux voir pourquoi; de nombreuses langues ont la même syntaxe et la même terminologie pour les deux opérations. Certaines langues peuvent même faire référence à toute conversion en tant que «casting», mais l’explication suivante se réfère aux concepts du CTS.

Si vous essayez d’affecter une valeur d’un type à un emplacement d’un type différent, vous pouvez générer une valeur du nouveau type qui a une signification similaire à l’original. C’est de la coercition. La coercition vous permet d’utiliser le nouveau type en créant une nouvelle valeur qui ressemble en quelque sorte à l’original. Certaines coercitions peuvent rejeter des données (par exemple, la conversion du entier 0x12345678 au court 0x5678), alors que d’autres peuvent ne pas le faire (par exemple, convertir le 0x00000008 int à 0x0008 court ou le 0x0000000000000008 long).

Rappelez-vous que les valeurs peuvent avoir plusieurs types. Si votre situation est légèrement différente et que vous souhaitez uniquement sélectionner un autre type de valeur, la diffusion est l’outil du travail. Casting indique simplement que vous souhaitez opérer sur un type particulier inclus dans une valeur.

La différence au niveau du code varie de C # à IL. En C #, le casting et la coercition sont assez similaires:

 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 assez 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 

En ce qui concerne le niveau logique, il existe des différences importantes. Le plus important à retenir est que la coercition crée une nouvelle valeur, alors que le casting ne le fait pas. L’identité de la valeur d’origine et la valeur après la conversion sont identiques, tandis que l’identité d’une valeur contrainte diffère de la valeur d’origine. la coersion crée une nouvelle instance distincte, alors que le casting ne le fait pas. Un corollaire est que le résultat du casting et de l’original sera toujours équivalent (à la fois en termes d’identité et d’égalité), mais une valeur contrainte peut être ou ne pas être identique à l’original et ne partage jamais l’identité d’origine.

Il est facile de voir les implications de la coercition dans les exemples ci-dessus, car les types numériques sont toujours copiés par valeur. Les choses deviennent un peu plus compliquées lorsque vous travaillez avec des types de référence.

 class Name : Tuple { public Name(ssortingng first, ssortingng last) : base(first, last) { } public static implicit operator ssortingng[](Name name) { return new ssortingng[] { name.Item1, name.Item2 }; } } 

Dans l’exemple ci-dessous, une conversion est une conversion, tandis que l’autre est une contrainte.

 Tuple tuple = name; ssortingng[] ssortingngs = name; 

Après ces conversions, le tuple et le nom sont égaux, mais les chaînes ne sont pas égales. Vous pouvez améliorer légèrement la situation (ou un peu plus de confusion) en implémentant Equals () et operator == () dans la classe Name pour comparer un nom et une chaîne de caractères []. Ces opérateurs «corrigeraient» le problème de la comparaison, mais vous auriez toujours deux instances distinctes; toute modification de chaîne ne serait pas reflétée dans le nom ou le tuple, alors que les modifications apscopes à l’un des noms ou à un tuple seraient reflétées dans le nom et le tuple, mais pas dans les chaînes.

Bien que l’exemple ci-dessus ait été conçu pour illustrer certaines différences entre le casting et la coercition, il constitue également un excellent exemple de la prudence avec laquelle vous devez utiliser des opérateurs de conversion avec des types de référence en C #.

Le casting préserve le type d’objects. La coercition ne le fait pas.

La coercition prend la valeur d’un type qui n’est PAS compatible avec l’affectation et convertit en un type compatible avec l’affectation. Ici, Int64 une coercition car Int32 n’hérite PAS d’ Int64 … donc ce n’est PAS une affectation compatible. Il s’agit d’une contrainte croissante (pas de perte de données). Une coercition grandissante est une conversion implicite. Une contrainte effectue une conversion.

 void Main() { System.Int32 a = 100; System.Int64 b = a; b.GetType();//The type is System.Int64. } 

Le casting vous permet de traiter un type comme s’il était d’un type différent tout en préservant le type .

  void Main() { Derived d = new Derived(); Base bb = d; //bN();//INVALID. Calls to the type Derived are not possible because bb is of type Base bb.GetType();//The type is Derived. bb is still of type Derived despite not being able to call members of Test } class Base { public void M() {} } class Derived: Base { public void N() {} } 

Source: Norme annotée d’infrastructure linguistique commune par James S. Miller

Maintenant, ce qui est étrange, c’est que la documentation de Microsoft sur Casting ne correspond pas à la définition de Casting de la spécification ecma-335.

Conversions explicites (conversions): les conversions explicites nécessitent un opérateur de dissortingbution. Le casting est requirejs lorsque des informations peuvent être perdues lors de la conversion ou lorsque la conversion peut échouer pour d’autres raisons. Des exemples typiques incluent la conversion numérique en un type moins précis ou avec une plage plus petite, et la conversion d’une instance de classe de base en une classe dérivée.

… Cela ressemble à des coercitions et non à des castings.

Par exemple,

  object o = 1; int i = (int)o;//Explicit conversions require a cast operator i.GetType();//The type has been explicitly converted to System.Int32. Object type is not preserved. This meets the definition of Coercion not casting. 

Qui sait? Peut-être que Microsoft vérifie si quelqu’un lit ce genre de choses.