Question

Dans le livre Learning C # de Jesse Liberty, il déclare & "Les objets d'un type peuvent être convertis en objets d'un autre type. Cela s'appelle le casting. & ";

Si vous examinez l'IL généré à partir du code ci-dessous, vous pouvez clairement voir que l'affectation exprimée ne fait pas la même chose que l'affectation convertie. Dans le premier cas, vous pouvez voir la boxe / unboxing se produire; dans ce dernier cas, vous pouvez voir un appel à une méthode de conversion.

Je sais qu’en fin de compte, ce n’est peut-être qu’une différence sémantique idiote - mais j’envisage simplement un autre mot pour la conversion. Je ne veux pas être sournois, mais je ne m'intéresse pas aux sentiments de qui que ce soit à ce sujet - les opinions ne comptent pas ici! Quelqu'un peut-il indiquer une référence définitive qui confirme ou nie si la conversion et la conversion sont identiques?

    object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

Merci

rp

Note ajoutée après le commentaire de Matt sur explicite / implicite:

Je ne pense pas que la différence soit implicite / explicite. Dans le code que j'ai posté, le changement est explicite dans les deux cas. Une conversion implicite est ce qui se produit lorsque vous affectez un short à un int.

Note à Sklivvz:

Je voulais confirmer que mes soupçons sur le flou du langage (normalement lucide et clair) de Jesse Liberty étaient corrects. Je pensais que Jesse Liberty était un peu lâche avec sa langue. Je comprends que le transtypage est routé dans la hiérarchie des objets - c’est-à-dire que vous ne pouvez pas transtyper d’un entier en une chaîne, mais vous pouvez transtyper d’une exception personnalisée dérivée de System.Exception en une exception System.Exception.

Il est toutefois intéressant de noter que lorsque vous essayez de convertir un entier en chaîne, le compilateur vous dit qu'il ne pourrait pas & "convertir &"; la valeur. Peut-être que Jesse est plus correct que je pensais!

Était-ce utile?

La solution

La réponse simple est: cela dépend.

Pour les types de valeur, la conversion impliquera une conversion réelle en un type différent. Par exemple:

float f = 1.5f;
int i = (int) f; // Conversion

Lorsque l'expression de casting est décochée, le résultat (en supposant que cela fonctionne) est habituellement juste une copie de ce qui était dans la boîte, avec le même type. Il existe toutefois des exceptions - vous pouvez décompresser d'un entier boxé en un enum (avec un type sous-jacent d'int) et vice versa; De même, vous pouvez décompresser d’un int en boîte à un Nullable < int >.

Lorsque l'expression de transtypage passe d'un type de référence à un autre et qu'aucune conversion définie par l'utilisateur n'est impliquée, il n'y a pas de conversion en ce qui concerne l'objet lui-même - seul le type de la référence changements " - et ce n’est vraiment que la manière dont la valeur est considérée, plutôt que la référence elle-même (qui seront les mêmes bits que précédemment). Par exemple:

object o = "hello";
string x = (string) o; // No data is "converted"; x and o refer to the same object

Lorsque des conversions définies par l'utilisateur sont impliquées, cela implique généralement de renvoyer un objet / une valeur différente. Par exemple, vous pouvez définir une conversion en chaîne pour votre propre type - et  ce ne serait certainement pas les mêmes données que votre propre objet. (Il peut s'agir bien sûr d'une chaîne existante déjà mentionnée dans votre objet.) D'après mon expérience, il existe généralement des conversions définies par l'utilisateur entre les types de valeur plutôt que les types de référence. Il s'agit donc rarement d'un problème.

Tous ces éléments sont considérés comme des conversions au sens de la spécification, mais ils ne sont pas tous considérés comme une conversion d'un objet en un objet d'un type différent. Je soupçonne qu’il s’agit d’un cas où Jesse Liberty n’a pas de terminologie; je l’ai remarqué dans la programmation C # 3.0 que je viens de lire.

Est-ce que cela couvre tout?

Autres conseils

Absolument pas!

Convert tente de vous obtenir un Int32 via & "Tous les moyens possibles &"; Cast ne fait rien de la sorte. Avec cast, vous dites au compilateur de traiter l'objet comme Int, sans conversion.

Vous devez toujours utiliser cast lorsque vous savez (de par sa conception) que l'objet est un Int32 ou une autre classe ayant un opérateur de transtypage sur Int32 (comme float, par exemple).

Convert devrait être utilisé avec String ou avec d'autres classes.

Essayez ceci

static void Main(string[] args)
{
    long l = long.MaxValue;

    Console.WriteLine(l);

    byte b = (byte) l;

    Console.WriteLine(b);

    b = Convert.ToByte(l);

    Console.WriteLine(b);

}

Résultat:

  

9223372036854775807

     

255

     

Exception non gérée:

     

System.OverflowException: la valeur est   supérieur à Byte.MaxValue ou inférieur   que Byte.MinValue à   System.Convert.ToByte (valeur Int64)   [0x00000] à Test.Main   (System.String [] args) [0x00019] dans   /home/marco/develop/test/Exceptions.cs:15

La meilleure explication que j'ai vue se trouve ci-dessous, suivie d'un lien vers la source:

& "; ... La vérité est un peu plus complexe que cela. .NET fournit trois méthodes pour aller du point A au point B, pour ainsi dire.

Premièrement, il y a la distribution implicite. Ceci est le casting qui ne vous obliger à faire autre chose qu'une mission:

int i = 5;
double d = i;

Celles-ci sont également appelées & "; élargissement des conversions &"; et .NET vous permet de les exécuter sans aucun opérateur de casting, car vous ne pourriez jamais perdre information le faire: la plage possible de valeurs valides d'un double englobe la plage de valeurs valides pour un int, puis quelques-unes, donc tu ne vas jamais faire cette mission et ensuite découvrir à votre horreur que le runtime ait perdu quelques chiffres de votre valeur int. Pour types de référence, la règle derrière un casting implicite est que le casting ne peut jamais lancer une exception InvalidCastException: il est clair pour le compilateur que la distribution est toujours valide.

Vous pouvez créer de nouveaux opérateurs de distribution implicite pour vos propres types (qui signifie que vous pouvez faire des conversions implicites qui enfreignent toutes les règles, si tu es stupide à ce sujet). La règle de base est qu'un implicite casting ne peut jamais inclure la possibilité de perdre des informations dans le transition.

Notez que la représentation sous-jacente a changé dans cette conversion: un double est représenté complètement différemment d'un int.

Le second type de conversion est une distribution explicite. Une distribution explicite est nécessaire chaque fois qu'il est possible de perdre des informations, ou il y a une possibilité que le casting pourrait ne pas être valide et donc jeter une exception InvalidCastException:

double d = 1.5;
int i = (int)d;

Ici, vous allez évidemment perdre des informations: je serai 1 après le jeté, donc le 0.5 se perd. Ceci est également connu sous le nom de & "; Rétrécissement &"; conversion, et le compilateur nécessite l’inclusion d’une conversion explicite (int) pour indiquer que oui, vous savez que des informations peuvent être perdues, mais vous vous en fichez.

De même, avec les types de référence, le compilateur nécessite des conversions explicites dans situations dans lesquelles la distribution peut ne pas être valide au moment de l'exécution, en tant que signal que oui, vous savez qu'il y a un risque, mais vous savez ce que vous faites.

Le troisième type de conversion est celui qui implique un changement aussi radical dans la représentation que les concepteurs ne fournissent même pas un explicite cast: ils vous font appeler une méthode pour faire la conversion:

string s = "15";
int i = Convert.ToInt32(s);

Notez qu'il n'y a rien qui nécessite absolument un appel de méthode ici. Les conversions implicites et explicites sont également des appels de méthode (c’est ainsi que vous effectuez le tien). Les concepteurs auraient pu très facilement créer une explicite opérateur de conversion qui a converti une chaîne en un entier. L'exigence que vous appelez une méthode est un choix stylistique plutôt qu'un principe fondamental exigence de la langue.

Le raisonnement stylistique ressemble à ceci: String-to-int est un conversion compliquée avec beaucoup d'opportunités horriblement faux:

string s = "The quick brown fox";
int i = Convert.ToInt32(s);

En tant que tel, l’appel de méthode vous donne la documentation à lire et un large indice que ceci est quelque chose de plus que juste un casting rapide.

Lorsque vous concevez vos propres types (en particulier vos propres types de valeur), vous peut décider de créer des opérateurs de casting et des fonctions de conversion. Les lignes divisant & "; conversion implicite &"; & "explicite &"; et & "fonction de conversion &"; territoire sont un peu flou, donc différentes personnes peuvent faire différentes décisions quant à ce qui devrait être quoi. Juste essayer de garder à l'esprit perte d'information et possibilité d'exceptions et de données non valides, et cela devrait vous aider à décider. & ";

  • Bruce Wood, le 16 novembre 2005

http://bytes.com/forum/post1068532-4.html

La diffusion implique des références

List<int> myList = new List<int>();
//up-cast
IEnumerable<int> myEnumerable = (IEnumerable<int>) myList;
//down-cast
List<int> myOtherList = (List<int>) myEnumerable;

Notez que les opérations sur myList, telles que l'ajout d'un élément, sont reflétées dans myEnumerable et myOtherList. En effet, elles font toutes référence (de types différents) à la même instance.

La conversion ascendante est sûre. Le down-casting peut générer des erreurs d'exécution si le programmeur a commis une erreur dans le type. La soustraction en toute sécurité dépasse le cadre de cette réponse.

La conversion implique des instances

List<int> myList = new List<int>();
int[] myArray = myList.ToArray();

myList est utilisé pour produire myArray. Il s’agit d’une conversion non destructive (myList fonctionne parfaitement après cette opération). Notez également que les opérations sur myList, telles que l'ajout d'un élément, ne sont pas reflétées dans myArray. C’est parce qu’il s’agit d’instances complètement séparées.

decimal w = 1.1m;
int x = (int)w;

réellement des conversions .

Hormis la sémantique, un test rapide montre qu’elles ne sont PAS équivalentes!
Ils effectuent la tâche différemment (ou peut-être différentes).

x=-2.5 (int)x=-2 Convert.ToInt32(x)=-2
x=-1.5 (int)x=-1 Convert.ToInt32(x)=-2
x=-0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 1.5 (int)x= 1 Convert.ToInt32(x)= 2
x= 2.5 (int)x= 2 Convert.ToInt32(x)= 2

Notez les cas x=-1.5 et x=1.5.

Une distribution indique au compilateur / interprète que l’objet est en fait de ce type (ou a un type / interface de base de ce type). C’est une chose assez rapide à faire par rapport à une conversion où ce n’est plus le compilateur / interprète qui fait le travail mais une fonction qui consiste à analyser une chaîne et à calculer en mathématique pour convertir en nombre.

Casting signifie toujours changer le type de données d'un objet. Cela peut être fait par exemple en convertissant une valeur flottante en valeur entière ou en réinterprétant les bits. Il s’agit généralement d’une opération supportée par le langage (lecture: prise en charge par le compilateur).

Le terme & conversion; " est parfois utilisé pour le casting, mais cela est généralement fait par une bibliothèque ou par votre propre code et ne donne pas nécessairement le même résultat que le casting. Par exemple, si vous avez une valeur en poids impérial et que vous la convertissez en poids métrique, elle peut rester du même type de données (par exemple, float), mais devenir un nombre différent. Un autre exemple typique est la conversion de degrés en radian.

Dans une manière de parler langage / framework-agnostic, la conversion d'un type ou d'une classe à une autre est appelée casting . Cela vaut également pour .NET, comme le montrent vos quatre premières lignes:

object x;
int y;

x = 4;

y = ( int )x;

Les langages de type C et C (tels que C #) utilisent la syntaxe (newtype)somevar pour la conversion. Dans VB.NET, par exemple, il existe des fonctions intégrées explicites pour cela. La dernière ligne serait écrite comme suit:

y = CInt(x)

Ou, pour les types plus complexes:

y = CType(x, newtype)

Où "C" est évidemment l'abréviation de "cast".

Cependant,

.NET a également la fonction Convert(). Ce n'est pas une fonctionnalité de langage intégrée (contrairement aux deux précédentes), mais plutôt un élément du framework. Cela devient plus clair lorsque vous utilisez un langage qui n'est pas nécessairement utilisé avec .NET: ils ont toujours très probablement leur propre moyen de diffusion, mais c'est .NET qui ajoute y.

Comme le dit Matt, la différence de comportement est que x est plus explicite. Plutôt que de simplement dire au compilateur de traiter <=> comme un équivalent entier de <=>, vous lui demandez spécifiquement de modifier <=> de manière à convenir à la classe d'entiers, then attribuer le résultat à <=>.

Dans votre cas particulier, le casting effectue ce que l’on appelle "unboxing", alors que <=> obtiendra la valeur entière. Le résultat sera le même, mais il existe de légères différences mieux expliquées par Keith . / p>

Selon le tableau 1-7 intitulé & "Méthodes de conversion explicite &"; à la page 55 du chapitre 1, leçon 4 de la trousse de formation personnalisée des SCTM (Examen 70-536): Microsoft & n ° 174; .NET Framework 2.0 & # 8212; Application Development Foundation , il existe certainement une différence entre elles.

System.Convert est indépendant de la langue et convertit & "; Les types qui implémentent l'interface System.IConvertible . &";

L'opérateur de diffusion (type) est une fonctionnalité du langage spécifique à C # qui convertit & "; Entre les types qui définissent les opérateurs de conversion . "

De plus, lors de la mise en œuvre de conversions personnalisées, les conseils diffèrent entre eux.

Conformément à la section Procédure d'implémentation de la conversion dans les types personnalisés , p. 56-57 de la leçon citée ci-dessus, les opérateurs de conversion (transtypage) sont destinés à simplifier les conversions entre types numériques. alors que Convert () active les conversions spécifiques à la culture .

  

La technique que vous choisissez dépend du type de conversion que vous souhaitez effectuer:

     
      
  • Définissez les opérateurs de conversion pour simplifier le rétrécissement et l'élargissement.   conversions entre types numériques.

  •   
  • Implémentez System.IConvertible pour permettre la conversion via   System.Convert. Utilisez cette technique pour activer les conversions spécifiques à une culture.

  •   
  • ...

  •   

Il devrait être plus clair maintenant que, puisque l'opérateur de conversion de conversion est implémenté séparément de l'interface IConvertible, Convert () n'est pas nécessairement simplement un autre nom pour la conversion. (Mais je peux imaginer où une mise en œuvre peut faire référence à une autre pour assurer la cohérence).

N'oubliez pas les autres méthodes de conversion et de conversion de variables: as, Parse, TryParse ainsi que la diffusion implicite entre les types de données compatibles.

Ce site propose un bon échantillon des résultats de la plupart des méthodes: C # Boxing et Unboxing

Donc, étant donné ces exemples de variables:

int i = 3, x;
long l;
string s = "5";

En principe, vous pouvez utiliser un transtypage implicite, entre deux types compatibles:

l = i;

Diffusion explicite à l'aide de l'unboxing ou du mot clé en tant que :

s = (string)i;
//or
s = i as string;

Conversions explicites à l'aide de méthodes de System.Convert:

i = System.Convert.ToInt32(s);

Conversions explicites à l'aide de méthodes à partir d'un type de données défini:

i = int.Parse(s);
i = int.TryParse(s, x);

Conversions explicites à l'aide de méthodes à partir d'une instance de variable:

s = i.ToString();

Je pense que le casting est simplement un moyen de définir des affectations entre deux types compatibles.

La conversion est nécessaire si vous devez copier explicitement une valeur d'un type incompatible dans un autre, sans pouvoir faire confiance à coercition perverse .

Quelques bonnes informations également sur MSDN: Conversions de conversions et de types

Casting consiste essentiellement à dire à l'exécution de & "faire semblant &"; l'objet est le nouveau type. En fait, il ne convertit ni ne modifie l'objet de quelque manière que ce soit.

Convertir, cependant, effectuera des opérations pour transformer un type en un autre.

À titre d'exemple:

char caster = '5';
Console.WriteLine((int)caster);

La sortie de ces instructions sera 53, car tout ce que le moteur d'exécution a fait est de regarder le modèle de bits et de le traiter comme un entier. Ce que vous obtenez finalement est la valeur ascii du caractère 5, plutôt que le nombre 5.

Si vous utilisez Convert.ToInt32 (caster), vous obtiendrez 5 car il lit la chaîne et la modifie correctement. (Essentiellement, il sait que la valeur ASCII 53 est vraiment la valeur entière 5.)

La différence est que la conversion soit implicite ou explicite. Le premier est un casting, le second est un appel plus explicite à une fonction qui convertit. Ils vont probablement faire la même chose de différentes manières.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top