En blogs de desarrollo, ejemplos de código en línea e (recientemente) incluso un libro, sigo tropezando con código como este:
var y = x as T;
y.SomeMethod();
o, peor aún:
(x as T).SomeMethod();
Eso no tiene sentido para mí. Si está seguro de que xes de tipo T, se debe utilizar un molde directo: (T)x. Si no está seguro, puede usarlo, aspero debe verificarnull antes de realizar alguna operación. Todo lo que hace el código anterior es convertir un (útil) InvalidCastExceptionen un (inútil) NullReferenceException.
¿Soy el único que piensa que esto es un abuso flagrante de la aspalabra clave? ¿O me perdí algo obvio y el patrón anterior realmente tiene sentido?
c#
casting
type-conversion
Heinzi
fuente
fuente

((T)x).SomeMethod(), ¿no? ;) (es broma, ¡tienes razón, por supuesto!)(f as T).SomeMethod()Respuestas:
Tu comprensión es verdadera. Eso suena como tratar de micro-optimizar para mí. Debe usar un yeso normal cuando esté seguro del tipo. Además de generar una excepción más sensata, también falla rápidamente. Si se equivoca sobre su hipótesis sobre el tipo, el programa fallará inmediatamente y usted será capaz de ver la causa del fracaso de inmediato en lugar de esperar a que una
NullReferenceExceptionoArgumentNullExceptionni siquiera un error lógico en algún momento en el futuro. En general, unaasexpresión que no es seguida por unnullcheque en alguna parte es un olor a código.Por otro lado, si no está seguro sobre el yeso y espera que falle, debe usarlo en
aslugar de un yeso normal envuelto con untry-catchbloque. Además,asse recomienda el uso de una verificación de tipo seguida de un yeso. En vez de:que genera una
isinstinstrucción para laispalabra clave y unacastclassinstrucción para el reparto (realizar efectivamente el reparto dos veces), debe usar:Esto solo genera una
isinstinstrucción. El primer método tiene una falla potencial en aplicaciones de subprocesos múltiples, ya que una condición de carrera puede hacer que la variable cambie su tipo después de que laisverificación se haya realizado correctamente y falle en la línea de lanzamiento. El último método no es propenso a este error.La siguiente solución no se recomienda para su uso en el código de producción. Si realmente odias una construcción tan fundamental en C #, podrías considerar cambiar a VB u otro lenguaje.
En caso de que uno odie desesperadamente la sintaxis del elenco, puede escribir un método de extensión para imitar el elenco:
y use una sintaxis ordenada [?]:
fuente
cacheobjeto que otro hilo intenta invalidar configurándolo ennull. En escenarios sin bloqueo, pueden surgir este tipo de cosas.Object. El uso del método en un tipo de valor hará que se encuadre innecesariamente.Tométodo aquí, ya que solo se convierte en la jerarquía de herencia, lo que para los tipos de valor implica el boxeo de todos modos. Por supuesto, toda la idea es más teórica que seria.En mi humilde opinión,
astiene sentido cuando se combina con unnullcheque:fuente
El uso de 'as' no aplica las conversiones definidas por el usuario, mientras que el elenco las usará cuando corresponda. Esa puede ser una diferencia importante en algunos casos.
fuente
Escribí un poco sobre esto aquí:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
Entiendo tu punto. Y estoy de acuerdo con el objetivo: que un operador de reparto comunica "Estoy seguro de que este objeto se puede convertir a ese tipo, y estoy dispuesto a arriesgar una excepción si me equivoco", mientras que un operador "como" se comunica "No estoy seguro de que este objeto se pueda convertir a ese tipo; dame un valor nulo si me equivoco".
Sin embargo, hay una sutil diferencia. (x como T). Lo que sea que () comunique "Sé no solo que x puede convertirse en una T, sino que, además, eso implica solo conversiones de referencia o unboxing y, además, que x no es nulo". Eso comunica información diferente a ((T) x). Lo que sea (), y quizás eso es lo que pretende el autor del código.
fuente
((T)x).Whatever()también comunica quexno está [destinado a ser] nulo, y dudo mucho que un autor normalmente se preocupe si la conversión seTproduce solo con conversiones de referencia o unboxing, o si requiere una conversión definida por el usuario o que cambie la representación. Después de todo, si lo definopublic static explicit operator Foo(Bar b){}, entonces es claramente mi intención la queBarse considera compatible conFoo. Es raro que quiera evitar esta conversión.A menudo he visto referencias a este artículo engañoso. como evidencia de que "as" es más rápido que el casting.
Uno de los aspectos engañosos más obvios de este artículo es el gráfico, que no indica lo que se está midiendo: sospecho que la medición ha fallado lanzamientos (donde "as" es obviamente mucho más rápido ya que no se produce ninguna excepción).
Si se toma el tiempo para hacer las mediciones, verá que el lanzamiento es, como era de esperar, más rápido que "como" cuando el lanzamiento tiene éxito.
Sospecho que esta puede ser una razón para el uso de "culto de carga" de la palabra clave como en lugar de un elenco.
fuente
El reparto directo necesita un par de paréntesis más que la
aspalabra clave. Entonces, incluso en el caso de que esté 100% seguro de cuál es el tipo, reduce el desorden visual.Sin embargo, estuvo de acuerdo en lo de la excepción. Pero al menos para mí, la mayoría de los usos de
asreducir se reducen para verificarnulldespués, lo que me parece más agradable que detectar una excepción.fuente
El 99% de las veces que uso "como" es cuando no estoy seguro de cuál es el tipo de objeto real
y no quiero capturar excepciones explícitas ni emitir dos veces, usando "is":
fuente
as. ¿Cuál es el otro 1%?Es solo porque a la gente le gusta cómo se ve, es muy legible.
Seamos realistas: el operador de conversión / conversión en lenguajes tipo C es bastante terrible, en cuanto a legibilidad. Me gustaría que C # adoptara la sintaxis Javascript de:
O defina un
tooperador, el equivalente de lanzamiento deas:fuente
dynamic_cast<>()(y similar). Estás haciendo algo feo, debería verse feo.A la gente le gusta
asmucho porque los hace sentir a salvo de las excepciones ... Como garantía en una caja. Un chico pone una garantía elegante en la caja porque quiere que te sientas cálido y tostado por dentro. Crees que pones esa cajita debajo de tu almohada por la noche, el Hada de la Garantía podría bajar y dejar un cuarto, ¿estoy en lo cierto, Ted?Volviendo al tema ... cuando se usa una transmisión directa, existe la posibilidad de una excepción de transmisión no válida. Por lo tanto, las personas se aplican
ascomo una solución general a todas sus necesidades de lanzamiento porqueas(por sí solo) nunca arrojará una excepción. Pero lo curioso de eso, está en el ejemplo que diste(x as T).SomeMethod();, está intercambiando una excepción de conversión no válida por una excepción de referencia nula. Lo que ofusca el verdadero problema cuando ves la excepción.Generalmente no uso
asdemasiado. Prefiero laisprueba porque, para mí, parece más legible y tiene más sentido que probar un yeso y verificar si es nulo.fuente
ascomo una solución general porque les hace sentirse seguras.Este tiene que ser uno de mis principales manías .
D&E de Stroustrup y / o alguna publicación de blog que no puedo encontrar en este momento discute la noción de un
tooperador que abordaría el punto hecho por https://stackoverflow.com/users/73070/johannes-rossel (es decir, la misma sintaxisaspero conDirectCastsemántica )La razón por la que esto no se implementó es porque un yeso debería causar dolor y ser feo, por lo que no podrá usarlo.
Lástima que los programadores 'inteligentes' (a menudo autores de libros (Juval Lowy IIRC)) lo eviten abusando
asde esta manera (C ++ no ofrece unaas, probablemente por esta razón).¡Incluso VB tiene más consistencia al tener una sintaxis uniforme que te obliga a elegir un
TryCastoDirectCasty tomar una decisión !fuente
DirectCastcomportamiento , no sintaxis .semanticsen su lugar: Pdouble-to-intlanzamiento que fallaría sidoubleno representara un valor exacto que pudiera caber en unInt32, pero tener un(int)-1.5rendimiento -1 es simplemente feo.MaybeValid<T>con dos campos públicosIsValidyValuequé código podría resolver como mejor le parezca. Eso hubiera permitido, por ejemploMaybeValid<TValue> TryGetValue(TKey key) { var ret = default(MaybeValid<TValue>); ret.IsValid = dict.TryGetValue(key, out ret.Value); return ret; }. Eso no solo ahorraría al menos dos operaciones de copia en comparaciónNullable<T>, sino que también podría valer con cualquier tipo, noTsolo clases.Creo que la
aspalabra clave podría considerarse como una versión más elegantedynamic_castde C ++.fuente
dynamic_casta C ++.std::bad_cast.static_castno realiza ninguna verificación del tipo de tiempo de ejecución. No hay un reparto similar a esto en C #.Probablemente sea más popular sin ninguna razón técnica, sino solo porque es más fácil de leer y más intuitivo. (No decir que lo hace mejor solo tratando de responder la pregunta)
fuente
Una razón para usar "como":
En lugar de (código incorrecto):
fuente
objsignificaría cambiar laobjvariable en sí para contener una referencia a otro objeto. No alteraría el contenido de la memoria en la que reside el objeto originalmente referenciado porobj. Este objeto original permanecería sin cambios, y latvariable aún tendría una referencia a él.