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 entièrement clairs sur la distinction.
Existe-t-il peut-être un moyen clair et simple d'expliquer la différence que vous connaissez?
conversion de type (également connu sous le nom de type cast)
Pour utiliser une valeur d'un type dans un contexte qui en attend un autre.
fonte de type non convertible (parfois appelée 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 requis par le contexte environnant.
La conversion Word fait référence à 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.
La contrainte Word est utilisée pour désigner une conversion implicite.
La conversion Word 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 bit- modèle ou une vraie conversion.
Ainsi, la contrainte est implicite, la conversion est explicite et la conversion est l'une d'entre elles.
Quelques exemples (de la même source ):
Contrainte (implicite):
double d;
int i;
if (d > i) d = i;
Distribution (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:
Un "cast" est l'utilisation d'un opérateur de cast. Un opérateur de cast 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 au moment de l'exécution; le compilateur doit traiter l'expression comme étant du type donné, et le runtime produira une erreur si ce n'est pas le cas, ou (2) l'expression est d'un type entièrement différent, mais il existe un moyen bien connu d'associer des instances du type de l'expression avec des instances du type transtypé. Le compilateur est chargé de générer du code qui effectue la conversion. Le lecteur attentif notera qu'il s'agit d'opposés, ce qui, à mon avis, est une astuce intéressante.
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 "changement de représentation", comme int pour doubler, ou il peut être "conservation de représentation" comme chaîne vers objet. Les conversions peuvent être "implicites", qui ne nécessitent pas de distribution, ou "explicites", qui nécessitent une distribution.
Une "coercition" est une conversion implicite qui change la représentation.
La conversion est le processus par lequel vous traitez un type d'objet comme un autre type. La contrainte consiste à convertir un objet en un autre.
Notez que dans l'ancien processus, aucune conversion n'est impliquée, vous avez un type que vous souhaitez traiter comme un autre, par exemple, vous avez 3 objets 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 êtes maintenant le type enfant spécifique, vous pouvez le mouler à ce qu'il est et utiliser toutes les méthodes et propriétés spécifiques de cet objet et cela ne créera pas une nouvelle instance de l'objet.
D'un autre côté, la contrainte implique la création d'un nouvel objet en mémoire du nouveau type, puis le type d'origine serait copié sur le nouveau, laissant les deux objets en mémoire (jusqu'à ce que les Garbage Collectors enlèvent l'un ou l'autre, ou les deux) .
Casting préserve le type d'objets. La coercition ne fonctionne pas.
La contrainte prend la valeur d'un type NON compatible avec les affectations et la convertit en un type compatible avec les affectations. Ici, j'exécute une contrainte parce que Int32
n'hérite PAS de Int64
... donc ce n'est PAS compatible avec les affectations. Il s'agit d'une coercition grandissante (aucune donnée perdue). Un élargissement de la contrainte est également une conversion implicite . Une coercition effectue une conversion.
void Main()
{
System.Int32 a = 100;
System.Int64 b = a;
b.GetType();//The type is System.Int64.
}
Casting vous permet de traiter un type comme s'il était d'un type différent tout en en préservant la tapez.
void Main()
{
Derived d = new Derived();
Base bb = d;
//b.N();//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: La norme annotée de l'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 spécification ecma-335 de Casting.
Conversions explicites (conversions): les conversions explicites nécessitent un opérateur de transtypage. La conversion est requise 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 qui a moins de précision ou une plage plus petite, et la conversion d'une instance de classe de base en une classe dérivée.
... Cela ressemble à Coercions pas Casting.
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 ces informations.
De la norme CLI :
I.8.3.2 Contrainte
Parfois, il est souhaitable de prendre une valeur d'un type qui n'est pas attribuable - à un emplacement, et de convertir la valeur en un type qui est attribuable - au type de l'emplacement. Ceci est accompli par contrainte de la valeur. La contrainte prend une valeur d'un type particulier et d'un type souhaité et tente de créer une valeur du type souhaité qui a une signification équivalente à la valeur d'origine. La contrainte peut entraîner un changement de représentation ainsi qu'un changement de type; la coercition ne préserve donc pas nécessairement l'identité de l'objet.
Il existe deux types de coercition: l'élargissement , qui ne perd jamais d'informations, et le rétrécissement , dans lequel des informations pourraient être perdues. Un exemple d'élargissement de la contrainte serait de contraindre une valeur qui est un entier signé 32 bits à une valeur qui est un entier signé 64 bits. Un exemple de rétrécissement de la contrainte est l'inverse: contraindre un entier signé 64 bits à un entier signé 32 bits. Les langages de programmation implémentent souvent l'élargissement des coercitions en tant que conversions implicites , tandis que le rétrécissement des coercitions nécessite généralement une conversion explicite .
Une certaine contrainte est intégrée directement dans les opérations VES sur les types intégrés (voir §I.12.1). Toute autre contrainte doit être explicitement demandée. Pour les types intégrés, le CTS fournit des opérations pour effectuer des contraintes d'élargissement sans vérification d'exécution et des contraintes de réduction avec vérification d'exécution ou troncature, selon la sémantique des opérations.
I.8.3.3 Casting
Puisqu'une valeur peut être de plusieurs types, une utilisation de la valeur doit identifier clairement lequel de ses types est utilisé. Étant donné que les valeurs sont lues à partir d'emplacements tapés, le type de la valeur utilisée est le type de l'emplacement à partir duquel la valeur a été lue. Si un type différent doit être utilisé, la valeur est transtypée en l'un de ses autres types. La conversion est généralement une opération de compilation, mais si le compilateur ne peut pas statiquement savoir que la valeur est du type cible, une vérification de la conversion à l'exécution est effectuée. Contrairement à la contrainte, une distribution ne change jamais le type réel d'un objet ni la représentation. Le casting préserve l'identité des objets.
Par exemple, une vérification de l'exécution peut être nécessaire lors du transtypage d'une valeur lue à partir d'un emplacement qui est tapé comme contenant une valeur d'une interface particulière. Étant donné qu'une interface est une description incomplète de la valeur, la conversion de cette valeur en un type d'interface différent entraînera généralement une vérification de la conversion au moment de l'exécution.
Ci-dessous une publication de l'article suivant :
La différence entre la contrainte et le lancer est souvent négligée. Je peux voir pourquoi; de nombreuses langues ont la même syntaxe (ou similaire) et la même terminologie pour les deux opérations. Certaines langues peuvent même qualifier toute conversion de "casting", mais l'explication suivante fait référence aux concepts de la CTS.
Si vous essayez d'affecter une valeur d'un certain 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 contrainte vous permet d'utiliser le nouveau type en créant une nouvelle valeur qui ressemble en quelque sorte à l'original. Certaines contraintes peuvent rejeter des données (par exemple, convertir l'int 0x12345678 en le court 0x5678), tandis que d'autres peuvent ne pas (par exemple convertir l'int 0x00000008 en le 0x0008 court ou le long 0x0000000000000008).
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, le casting est l'outil idéal pour le travail. La diffusion 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
Quant au niveau logique, il existe des différences importantes. Le plus important à retenir est que la coercition crée une nouvelle valeur, contrairement au casting. L'identité de la valeur d'origine et la valeur après la coulée sont les mêmes, tandis que l'identité d'une valeur contrainte diffère de la valeur d'origine; la coersion crée une nouvelle instance distincte, contrairement à la conversion. Un corollaire est que le résultat du casting et l'original seront toujours équivalents (à la fois en termes d'identité et d'égalité), mais une valeur contrainte peut ou non ê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, 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<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 conversion, tandis que l'autre est une contrainte.
Tuple<string, string> Tuple = name;
string[] strings = name;
Après ces conversions, Tuple et nom sont égaux, mais les chaînes ne sont égales à aucun d'eux. Vous pouvez rendre la situation légèrement meilleure (ou légèrement plus confuse) en implémentant Equals () et l'opérateur == () sur la classe Name pour comparer un Name et une chaîne []. Ces opérateurs "résoudraient" le problème de comparaison, mais vous auriez toujours deux instances distinctes; toute modification des chaînes ne serait pas reflétée dans le nom ou le tuple, tandis que les modifications apportées à l'un des nom ou Tuple seraient reflétées dans le nom et le tuple, mais pas dans les chaînes.
Bien que l'exemple ci-dessus soit destiné à illustrer certaines différences entre la conversion et la coercition, il sert également de bon exemple de la raison pour laquelle vous devez être extrêmement prudent lorsque vous utilisez des opérateurs de conversion avec des types de référence en C #.
Selon Wikipedia,
En informatique, la conversion de type, la conversion de type, la coercition de type et le jonglage de type sont différentes façons de changer une expression d'un type de données à un autre.
La différence entre la coulée de caractères et la contrainte de type est la suivante:
TYPE CASTING | TYPE COERCION
|
1. Explicit i.e., done by user | 1. Implicit i.e., done by the compiler
|
2. Types: | 2. Type:
Static (done at compile time) | Widening (conversion to higher data
| type)
Dynamic (done at run time) | Narrowing (conversion to lower data
| type)
|
3. Casting never changes the | 3. Coercion can result in representation
the actual type of object | as well as type change.
nor representation. |
Remarque: la diffusion n'est pas une conversion. C'est juste le processus par lequel nous traitons un type d'objet comme un autre type. Par conséquent, le type d'objet réel, ainsi que la représentation, ne sont pas modifiés lors de la coulée.
Je suis d'accord avec les mots de @ PedroC88:
D'un autre côté, la contrainte implique la création d'un nouvel objet en mémoire du nouveau type, puis le type d'origine serait copié sur le nouveau, laissant les deux objets en mémoire (jusqu'à ce que les Garbage Collectors enlèvent l'un ou l'autre, ou les deux) .