Dans les blogs de développement, les exemples de code en ligne et (récemment) même un livre, je continue de trébucher sur le code comme ceci:
var y = x as T;
y.SomeMethod();
ou pire encore:
(x as T).SomeMethod();
Cela n'a aucun sens pour moi. Si vous êtes sûr x
est de type T
, vous devez utiliser une distribution directe: (T)x
. Si vous n'êtes pas sûr, vous pouvez utiliser as
mais devez vérifier null
avant d'effectuer une opération. Tout ce que fait le code ci-dessus est de transformer un (utile) InvalidCastException
en (inutile) NullReferenceException
.
Suis-je le seul à penser que c'est un abus flagrant du as
mot-clé? Ou ai-je raté quelque chose d'évident et le schéma ci-dessus a-t-il du sens?
c#
casting
type-conversion
Heinzi
la source
la source
((T)x).SomeMethod()
, non? ;) (je plaisante, vous avez raison bien sûr!)(f as T).SomeMethod()
Réponses:
Votre compréhension est vraie. Cela ressemble à essayer de micro-optimiser pour moi. Vous devez utiliser un casting normal lorsque vous êtes sûr du type. En plus de générer une exception plus sensible, il échoue également rapidement. Si vous vous trompez sur votre hypothèse sur le type, votre programme échouera immédiatement et vous pourrez voir la cause de l'échec immédiatement plutôt que d'attendre une
NullReferenceException
ouArgumentNullException
ou même une erreur logique dans le futur. En général, uneas
expression qui n'est pas suivie d'unenull
vérification quelque part est une odeur de code.D'un autre côté, si vous n'êtes pas sûr de la distribution et que vous vous attendez à ce qu'elle échoue, vous devez utiliser à la
as
place d'une distribution normale enveloppée d'untry-catch
bloc. De plus, l'utilisation deas
est recommandée par rapport à une vérification de type suivie d'un plâtre. Au lieu de:qui génère une
isinst
instruction pour leis
mot - clé et unecastclass
instruction pour le casting (exécutant effectivement le casting deux fois), vous devez utiliser:Cela ne génère qu'une
isinst
instruction. La première méthode présente un défaut potentiel dans les applications multithread car une condition de concurrence peut entraîner le changement de type de la variable après lais
réussite de la vérification et l'échec de la ligne de distribution. Cette dernière méthode n'est pas sujette à cette erreur.La solution suivante n'est pas recommandée pour une utilisation dans le code de production. Si vous détestez vraiment une construction aussi fondamentale en C #, vous pourriez envisager de passer à VB ou à un autre langage.
Dans le cas où l'on déteste désespérément la syntaxe du cast, il / elle peut écrire une méthode d'extension pour imiter le cast:
et utilisez une syntaxe [?] soignée:
la source
cache
objet qu'un autre thread essaie de invalider en le définissant surnull
. Dans les scénarios sans verrouillage, ce genre de choses peut survenir.Object
. L'utilisation de la méthode sur un type de valeur entraînera sa mise en boîte inutilement.To
méthode ici, car il ne se convertit qu'à travers la hiérarchie d'héritage, qui pour les types de valeur implique de toute façon la boxe. Bien sûr, l'idée dans son ensemble est plus théorique que sérieuse.À mon humble avis, il
as
suffit d'avoir du sens lorsqu'il est combiné avec unnull
chèque:la source
L'utilisation de "as" n'applique pas les conversions définies par l'utilisateur, tandis que la distribution les utilisera le cas échéant. Cela peut être une différence importante dans certains cas.
la source
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: qu'un opérateur de cast communique "Je suis sûr que cet objet peut être converti en ce type, et je suis prêt à risquer une exception si je me trompe", alors qu'un opérateur "as" communique "Je ne suis pas sûr que cet objet puisse être converti dans ce type; donnez-moi une valeur nulle si je me trompe".
Cependant, il existe une différence subtile. (x as T). Quoi que () communique "Je sais non seulement que x peut être converti en T, mais en plus, cela implique seulement des conversions de référence ou de déballage, et en plus, que x n'est pas nul". Cela communique des informations différentes de ((T) x). Quoi que (), et c'est peut-être ce que l'auteur du code a l'intention de faire.
la source
((T)x).Whatever()
également quix
n'est pas [censé être] nul, et je doute fortement qu'un auteur se soucie généralement de savoir si la conversion seT
produit uniquement avec des conversions de référence ou de décodage, ou si elle nécessite une conversion définie par l'utilisateur ou qui change la représentation. Après tout, si je le définispublic static explicit operator Foo(Bar b){}
, c'est clairement mon intention qui doitBar
être considérée comme compatible avecFoo
. Il est rare que je veuille éviter cette conversion.J'ai souvent vu des références à cet article trompeur comme une preuve que "as" est plus rapide que le 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 qu'il mesure les transformations échouées (où "as" est évidemment beaucoup plus rapide car aucune exception n'est levée).
Si vous prenez le temps de faire les mesures, vous verrez que le lancer est, comme vous vous en doutez, plus rapide que "as" lorsque le lancer réussit.
Je soupçonne que cela peut être l'une des raisons de l'utilisation du mot-clé as par "culte du fret" au lieu d'un casting.
la source
Le casting direct a besoin d'une paire de parenthèses de plus que le
as
mot clé. Ainsi, même dans le cas où vous êtes sûr à 100% du type, cela réduit l'encombrement visuel.Mais je suis d'accord sur l'exception. Mais au moins pour moi, la plupart des utilisations de l'
as
ébullition se vérifient par lanull
suite, ce que je trouve plus agréable que d'attraper une exception.la source
99% du temps quand j'utilise "comme" c'est quand je ne suis pas sûr quel est le type d'objet réel
et je ne veux pas intercepter les exceptions de cast explicites ni faire de cast deux fois, en utilisant "is":
la source
as
. Quel est l'autre 1%?C'est juste parce que les gens aiment son apparence, c'est très lisible.
Avouons-le: l'opérateur de conversion / conversion dans les langages de type C est assez terrible, en termes de lisibilité. J'aimerais mieux que C # adopte la syntaxe Javascript de:
Ou définissez un
to
opérateur, l'équivalent de casting deas
:la source
dynamic_cast<>()
(et similaire). Vous faites quelque chose de laid, cela devrait paraître laid.Les gens aiment
as
tellement parce 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 tout chaud et grillé à l'intérieur. Vous pensez que vous avez mis cette petite boîte sous votre oreiller la nuit, la fée de garantie pourrait descendre et quitter un quart, ai-je raison Ted?Retour sur le sujet ... lors de l'utilisation d'un cast direct, il existe la possibilité d'une exception de cast non valide. Ainsi, les gens postulent en
as
tant que solution globale à tous leurs besoins en matière de casting, caras
(en eux-mêmes) ne lèveront jamais d'exception. Mais ce qui est drôle, c'est que dans l'exemple que vous avez donné,(x as T).SomeMethod();
vous échangez une exception de distribution non valide contre une exception de référence nulle. Ce qui obscurcit le vrai problème lorsque vous voyez l'exception.Je n'en utilise généralement pas
as
trop. Je préfère leis
test car il me semble plus lisible et plus logique que d'essayer un cast et de vérifier null.la source
as
une demande globale, car ils se sentent en sécurité.Cela doit être l'un de mes coups de cœur .
Le D&E de Stroustrup et / ou un article de blog que je ne peux pas trouver en ce moment traite de la notion d'un
to
opérateur qui répondrait au point soulevé par https://stackoverflow.com/users/73070/johannes-rossel (c'est-à-dire, même syntaxe queas
mais avec laDirectCast
sémantique ).La raison pour laquelle cela n'a pas été implémenté est parce qu'un casting devrait causer de la douleur et être laid, donc vous êtes poussé à ne pas l'utiliser.
Dommage que des programmeurs «intelligents» (souvent des auteurs de livres (Juval Lowy IIRC)) contournent cela en abusant
as
de cette façon (C ++ n'en offre pasas
, probablement pour cette raison).Même VB a une plus grande cohérence d'avoir une syntaxe uniforme qui vous oblige à choisir un
TryCast
ouDirectCast
et faites votre esprit !la source
DirectCast
comportement , pas de syntaxe .semantics
place: Pdouble-to-int
cast qui échouerait si ledouble
ne représentait pas une valeur exacte qui pourrait tenir dans unInt32
, mais avoir un(int)-1.5
rendement -1 est tout simplement moche.MaybeValid<T>
avec deux champs publicsIsValid
etValue
quel code pourrait faire comme bon lui semble. Cela aurait permis par exempleMaybeValid<TValue> TryGetValue(TKey key) { var ret = default(MaybeValid<TValue>); ret.IsValid = dict.TryGetValue(key, out ret.Value); return ret; }
. Non seulement cela permettrait d'économiser au moins deux opérations de copie par rapport àNullable<T>
, mais cela pourrait également valoir pour n'importe quel type -T
pas seulement les classes.Je crois que le
as
mot - clé pourrait être considéré comme une version plus élégantedynamic_cast
du C ++.la source
dynamic_cast
à C ++.std::bad_cast
.static_cast
aucune vérification de type d'exécution. Il n'y a pas de distribution similaire à cela en C #.Il est probablement plus populaire sans raison technique, mais simplement parce qu'il est plus facile à lire et plus intuitif. (Ne pas dire que cela améliore, juste essayer de répondre à la question)
la source
Une raison d'utiliser "as":
Au lieu de (mauvais code):
la source
obj
signifierait changer laobj
variable elle-même pour contenir une référence à un autre objet. Il ne modifierait pas le contenu de la mémoire à laquelle réside l'objet référencé à l'origine parobj
. Cet objet d'origine resterait inchangé et lat
variable contiendrait toujours une référence à lui.