web-dev-qa-db-fra.com

Est-il judicieux d’utiliser "comme" au lieu d’un casting même s’il n’ya pas de contrôle nul?

Dans les blogs de développement, les exemples de code en ligne et (récemment) même un livre, je n'arrête pas de trébucher sur un code comme celui-ci:

var y = x as T;
y.SomeMethod();

ou pire encore:

(x as T).SomeMethod();

Cela n'a pas de sens pour moi. Si vous êtes sûr que x est de type T, vous devez utiliser une conversion directe: (T)x. Si vous n'êtes pas sûr, vous pouvez utiliser as mais vous devez vérifier null avant d'effectuer une opération. Le code ci-dessus ne fait que transformer un (utile) InvalidCastException en un (inutile) NullReferenceException.

Suis-je le seul à penser qu'il s'agit d'un abus flagrant du mot clé as? Ou ai-je oublié quelque chose d'évident et le modèle ci-dessus a-t-il un sens?

349
Heinzi

Votre compréhension est vraie. Cela ressemble à essayer de micro-optimiser pour moi. Vous devez utiliser une distribution normale lorsque vous êtes sûr du type. En plus de générer une exception plus sensible, elle échoue également rapidement. Si vous vous trompez au sujet de votre hypothèse sur le type, votre programme échouera immédiatement et vous pourrez voir immédiatement la cause de l'échec plutôt que d'attendre un NullReferenceException ou ArgumentNullException ou même une erreur logique dans le futur. En général, une expression as qui n'est pas suivie d'un contrôle null est une odeur de code.

D'un autre côté, si vous n'êtes pas sûr du cast et que vous vous attendez à ce qu'il échoue, vous devriez utiliser as au lieu d'un cast normal entouré d'un try-catch bloquer. De plus, l'utilisation de as est recommandée par rapport à une vérification de type suivie d'un transtypage. Au lieu de:

if (x is SomeType)
   ((SomeType)x).SomeMethod();

qui génère une instruction isinst pour le mot clé is, et une instruction castclass pour la conversion (effectuant effectivement la jeté deux fois), vous devez utiliser:

var v = x as SomeType;
if (v != null)
    v.SomeMethod();

Cela ne génère qu'une instruction isinst. L'ancienne méthode présente un risque potentiel dans les applications multithreads, car une condition de concurrence critique pourrait amener la variable à changer de type après le contrôle de is et l'échec de la chaîne de distribution. La dernière méthode n'est pas sujette à cette erreur.


La solution suivante est non recommandée pour une utilisation dans le code de production. Si vous détestez vraiment une construction aussi fondamentale en C #, vous pouvez envisager de passer à VB ou à un autre langage).

Si on déteste désespérément la syntaxe du casting, il/elle peut écrire une méthode d'extension pour imiter le casting:

public static T To<T>(this object o) { // Name it as you like: As, Cast, To, ...
    return (T)o;
}

et utilisez une syntaxe soignée [?]:

obj.To<SomeType>().SomeMethod()
250
Mehrdad Afshari

IMHO, as prend tout son sens lorsqu'il est combiné avec un contrôle null:

var y = x as T;
if (y != null)
    y.SomeMethod();
42
Rubens Farias

L'utilisation de "comme" ne s'applique pas aux conversions définies par l'utilisateur, alors que la distribution les utilisera le cas échéant. Cela peut être une différence importante dans certains cas.

39
Larry Fix

J'ai écrit un peu à ce sujet ici:

http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

Je comprends votre point. Et je suis d’accord avec l’idée maîtresse: un opérateur de casting communique "Je suis sûr que cet objet peut être converti en ce type, et je suis disposé à risquer une exception si je me trompe", alors qu’un opérateur "en" communique "Je ne suis pas sûr que cet objet puisse être converti en ce type; donnez-moi une valeur nulle si je me trompe".

Cependant, il y a une différence subtile. (x comme T) .W Whatever () communique "Je sais que x ne peut pas seulement être converti en T, mais que cela implique uniquement des conversions de référence ou unboxing, et que x n'est pas nul". Cela communique des informations différentes de celles de ((T) x) .W Whatever (), et c’est peut-être ce que l’intention de l’auteur du code.

36
Eric Lippert

J'ai souvent vu des références à cet article trompeur comme preuve que "en tant que" est plus rapide qu'un casting.

L'un des aspects trompeurs les plus évidents de cet article est le graphique, qui n'indique pas ce qui est mesuré: je soupçonne que sa mesure a échoué jette (où " comme "est évidemment beaucoup plus rapide car aucune exception n’est levée).

Si vous prenez le temps de faire les mesures, alors vous verrez que le casting est, comme on peut s'y attendre, plus rapide que "comme" lorsque le casting réussit.

Je soupçonne que cela pourrait être l’une des raisons du "culte de la cargaison": utiliser le mot-clé en tant que mot clé au lieu d’un casting.

16
Joe

La diffusion directe nécessite une paire de parenthèses plus que le mot clé as. Ainsi, même dans le cas où vous êtes à 100% sûr du type, cela réduit l'encombrement visuel.

Convenu sur la chose d'exception, cependant. Mais au moins pour moi, la plupart des utilisations de as se résument à vérifier après null, ce que je trouve plus agréable que d’attraper une exception.

11
Joey

C'est simplement parce que les gens aiment son apparence, c'est très lisible.

Regardons les choses en face: l’opérateur de casting/conversion dans les langages de type C est assez terrible en termes de lisibilité. Je préférerais que C # adopte la syntaxe Javascript suivante:

object o = 1;
int i = int(o);

Ou définissez un opérateur to, l’équivalent de as:

object o = 1;
int i = o to int;
8
JulianR

99% du temps quand j'utilise "comme", c'est quand je ne suis pas sûr du type d'objet réel

var x = obj as T;
if(x != null){
 //x was type T!
}

et je ne veux pas attraper les exceptions de casting explicites ni faire un casting deux fois, en utilisant "est":

//I don't like this
if(obj is T){
  var x = (T)obj; 
}
8
Max Galkin

Les gens aiment tellement as que cela les met à l’abri des exceptions ... Comme une garantie sur une boîte. Un gars met une garantie de fantaisie sur la boîte parce qu'il veut que vous vous sentiez au chaud et au chaud à l'intérieur. Vous pensez que vous mettez cette petite boîte sous votre oreiller la nuit, la fée garantie pourrait descendre et laisser un quart, est-ce que j'ai raison Ted?

Retour sur le sujet ... lors de l'utilisation d'une diffusion directe, il existe la possibilité pour une exception de distribution non valide. Donc, les gens appliquent as comme solution globale à tous leurs besoins en termes de casting parce que as (en lui-même) ne lèvera jamais une exception. Mais la chose amusante à ce sujet est dans l'exemple que vous avez donné (x as T).SomeMethod(); vous échangez une exception de distribution non valide pour une exception de référence null. Ce qui brouille le vrai problème quand on voit l'exception.

En général, je n'utilise pas trop as. Je préfère le test is car il me semble plus lisible et plus logique que d'essayer un cast et de rechercher la valeur null.

5
Bob

Ce doit être l'un de mes top peeves .

Le D & E de Stroustrup et/ou un article de blog que je ne trouve pas en ce moment aborde la notion d'opérateur to qui répondrait au point soulevé par https://stackoverflow.com/users/73070/johannes- rossel (c'est-à-dire, même syntaxe que as mais avec DirectCast sémantique).

La raison pour laquelle cela n’a pas été mis en œuvre est qu’un casting devrait causer de la douleur et être laid, de sorte que l’on l’éloigne de l’utiliser.

Dommage que des programmeurs "intelligents" (souvent des auteurs de livres (Juval Lowy IIRC)) évitent cela en abusant de as de cette manière (le C++ ne propose pas de as, probablement pour cette raison).

Même VB a plus de cohérence dans le fait d'avoir une syntaxe uniforme qui vous oblige à choisir un TryCast ou DirectCast et composent votre esprit !

5
Ruben Bartelink

Je pense que le mot-clé as pourrait être considéré comme une version plus élégante du thème dynamic_cast depuis C++.

2
Andrew Garrison

C'est probablement plus populaire sans raison technique mais simplement parce que c'est plus facile à lire et plus intuitif. (Ne pas dire que ça le rend préférable d'essayer juste de répondre à la question)

1
Jla

Une des raisons d'utiliser "en tant que":

T t = obj as T;
 //some other thread changes obj to another type...
if (t != null) action(t); //still works

Au lieu de (mauvais code):

if (obj is T)
{
     //bang, some other thread changes obj to another type...
     action((T)obj); //InvalidCastException
}
1
Rauhotz