web-dev-qa-db-fra.com

C # "en tant que" casting vs casting classique

Duplicate possible:
Casting vs en utilisant le mot clé 'as' dans le CLR

J'ai récemment appris une autre façon de lancer. Plutôt que d'utiliser

SomeClass someObject = (SomeClass) obj;

on peut utiliser cette syntaxe:

SomeClass someObject = obj as SomeClass;

qui semble renvoyer null si obj n'est pas une SomeClass, plutôt que de lancer une exception de conversion de classe.

Je vois que cela peut conduire à une exception NullReferenceException si la conversion a échoué et que j'essaie d'accéder à la variable someObject. Je me demande donc quelle est la raison d'être de cette méthode? Pourquoi devrait-on utiliser cette manière de transtyper plutôt que (l'ancienne) - cela ne semble que déplacer le problème d'un cast manquant "plus profondément" dans le code.

124
Chris

Avec la méthode "classique", en cas d'échec de la conversion, une exception est générée. Avec la méthode as, il en résulte une valeur null qui peut être vérifiée et éviter une exception.

En outre, vous ne pouvez utiliser "que" avec les types de référence. Par conséquent, si vous convertissez un type de valeur en un type de valeur, vous devez toujours utiliser la méthode "classique".

Note:

La méthode as ne peut être utilisée que pour les types auxquels on peut attribuer une valeur null. Cela signifiait uniquement les types de référence, mais lorsque .NET 2.0 est sorti, il introduisait le concept d'un type de valeur nullable. Étant donné que ces types peuvent recevoir une valeur null, ils sont valides pour une utilisation avec l'opérateur as.

155
Brian Ball

Une comparaison nulle est BEAUCOUP plus rapide que de lancer et de capturer une exception. Les exceptions ont un temps système important - la trace de pile doit être assemblée, etc.

Les exceptions devraient représenter un état inattendu, ce qui ne représente souvent pas la situation (c'est le moment où as fonctionne mieux).

31
Matěj Zábský

Dans certains cas, il est facile de traiter avec un null qu'une exception. En particulier, l'opérateur de coalescence est pratique:

SomeClass someObject = (obj as SomeClass) ?? new SomeClass();

Cela simplifie également le code où vous vous trouvez (sans polymorphisme) et en créant des branches en fonction du type d'objet:

ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
    // use a
}
else if ((b = obj as ClassB) != null)
{
    // use b
}

Comme spécifié sur la page MSDN , l'opérateur as équivaut à:

expression is type ? (type)expression : (type)null

ce qui évite complètement l’exception au profit d’un test de type plus rapide, mais limite également son utilisation aux types qui supportent null (types de référence et Nullable<T>).

27
Zooba

L'opérateur as est utile dans quelques circonstances.

  1. Quand vous devez seulement savoir qu'un objet est d'un type spécifique mais que vous n'avez pas besoin d'agir spécifiquement sur des membres de ce type
  2. Lorsque vous souhaitez éviter les exceptions et traiter explicitement avec null
  3. Vous voulez savoir s'il existe une conversion CLR entre les objets et pas seulement une conversion définie par l'utilisateur.

Le 3ème point est subtil mais important. Il n’existe pas de correspondance 1-1 entre les conversions qui réussiront avec l’opérateur de conversion et celles qui réussiront avec l’opérateur as. L'opérateur as est strictement limité aux conversions CLR et ne prendra pas en compte les conversions définies par l'utilisateur (l'opérateur de diffusion le fera).

Plus précisément, l'opérateur as ne permet que les opérations suivantes (à partir de la section 7.9.11 de la spécification de langage C #)

  • Une conversion d'identité (§6.1.1), de référence implicite (§6.1.6), de boxe (§6.1.7), de référence explicite (§6.2.4) ou de déballage (§6.2.5) existe à partir du type de E à T.
  • Le type de E ou T est un type ouvert.
  • E est le littéral nul.
7
JaredPar

Le mot clé as est utile lorsque vous utilisez réellement ne sait pas quel type de variable pourrait être. Si vous avez une seule fonction qui suivra des chemins de code différents en fonction du type réel du paramètre, vous avez deux choix:

Tout d'abord, en utilisant un casting normal:

if(myObj is string)
{
    string value = (string)myObj;

    ... do something
}
else if(myObj is MyClass)
{
    MyClass = (MyClass)myObj;
}

Cela nécessite que vous vérifiiez le type de l'objet en utilisant is afin que vous n'essayiez pas de le convertir en quelque chose qui échouera. Ceci est également légèrement redondant, car la vérification du type is- est effectuée à nouveau dans le transtypage (afin de pouvoir lever l'exception si nécessaire).

L'alternative consiste à utiliser as.

string myString = myObj as string;
MyClass myClass = myObj as MyClass;

if(myString != null)
{

}
else if(myClass != null)
{

}

Cela raccourcit quelque peu le code et élimine également la vérification de type redondante.

3
Adam Robinson

Je pense que la meilleure "règle" serait de n'utiliser le mot-clé "en tant que" que s'il est prévu que votre sujet ne sera pas l'objet vers lequel vous lancez le message:

var x = GiveMeSomething();

var subject = x as String;

if(subject != null)
{
  // do what you want with a string
}
else
{
  // do what you want with NOT a string
}

Cependant, lorsque votre sujet DEVRAIT être du type que vous souhaitez utiliser, utilisez un "casting classique", comme vous l'appelez. Parce que si ce n'est pas le type que vous attendez, vous obtiendrez une exception qui correspond à la situation exceptionnelle.

1
Erik van Brakel

utiliser as retournera null si ce n'est pas un cast valide qui vous permet de faire autre chose que de placer le casting dans un try/catch. Je déteste le casting classique. J'utilise toujours comme casting si je ne suis pas sûr. De plus, les exceptions sont chères. Les contrôles nuls ne le sont pas.

1
Dustin Davis

Je suppose que cela est utile si le résultat de la conversion sera passé à une méthode qui gérera les références nulles sans lancer ni ArgumentNullException ou similaire.

J'ai tendance à trouver très peu d'utilité pour as, car:

obj as T

Est plus lent que:

if (obj is T)
    ...(T)obj...

L'utilisation de as est vraiment un scénario Edge-case pour moi, donc je ne peux pas imaginer de règles générales pour le moment où je l'utiliserais plus que de lancer et de gérer l'exception (plus informative) de casting plus haut la pile.

0
Quick Joe Smith

Il n’ya rien de profond qui se passe ici. En gros, il est pratique de tester quelque chose pour voir s’il s’agit d’un certain type (c’est-à-dire utiliser 'en tant que'). Vous voudriez vérifier le résultat de l'appel 'en tant que' pour voir si le résultat est null.

Si vous souhaitez qu’une distribution fonctionne et que vous souhaitez que l’exception soit levée, utilisez la méthode "classique".

0
RQDQ

Vous utilisez l'instruction "en tant que" pour éviter la possibilité d'une exception, par exemple. vous pouvez gérer l'échec de la distribution avec élégance via la logique. Utilisez le casting uniquement lorsque vous êtes sûr que l'objet est du type souhaité. J'utilise presque toujours le "comme" puis vérifie la valeur null.

0
Keith Bluestone