¿Tiene sentido utilizar “como” en lugar de un molde incluso si no hay un cheque nulo?

En blogs de desarrollo, ejemplos de código en línea y (recientemente) incluso un libro, sigo tropezando con un 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 x es de tipo T , debe usar un molde directo: (T)x . Si no está seguro, puede utilizarlo as pero debe verificar si es null antes de realizar alguna operación. Todo lo que hace el código anterior es convertir una InvalidCastException (útil) en una (inútil) NullReferenceException .

¿Soy el único que piensa que esto es un abuso flagrante de la palabra clave as ? ¿O me perdí algo obvio y el patrón anterior realmente tiene sentido?

Tu comprensión es verdad Eso suena como tratar de micro-optimizar para mí. Deberías usar un yeso normal cuando estés seguro del tipo. Además de generar una excepción más sensible, también falla rápidamente. Si se equivoca acerca de su suposición sobre el tipo, su progtwig fallará inmediatamente y podrá ver la causa de la falla de forma inmediata en lugar de esperar una NullReferenceException o ArgumentNullException o incluso un error lógico en algún momento en el futuro. En general, una expresión as que no es seguida por un cheque null alguna parte es un olor a código.

Por otro lado, si no estás seguro acerca del reparto y esperas que falle, debes utilizarlo as lugar de un molde normal envuelto con un bloque try-catch . Además, se recomienda el uso de as en lugar de un control de tipo seguido de un molde. En lugar de:

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

que genera una instrucción isinst para la palabra clave is , y una instrucción de castclass para el reparto (que realiza el reparto dos veces), debe usar:

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

Esto solo genera una instrucción más isinst . El primer método tiene un defecto potencial en las aplicaciones multiproceso, ya que una condición de carrera puede hacer que la variable cambie su tipo después de que la verificación sea exitosa y falle en la línea de transmisión. 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 idioma.

En caso de que uno odie desesperadamente la syntax del elenco, él / ella puede escribir un método de extensión para imitar el elenco:

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

y use una syntax limpia [?]:

 obj.To().SomeMethod() 

En mi humilde opinión, simplemente tiene sentido cuando se combina con un cheque null :

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

El uso de ‘como’ no aplica las conversiones definidas por el usuario, mientras que el reparto las usará cuando corresponda. Esa puede ser una diferencia importante en algunos casos.

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 impulso de esto: que un operador de reparto comunique “estoy seguro de que este objeto se puede convertir a ese tipo, y estoy dispuesto a arriesgar una excepción si estoy equivocado”, mientras que un operador “como” se comunica “No estoy seguro de que este objeto se pueda convertir a ese tipo; dame un nulo si me equivoco”.

Sin embargo, hay una diferencia sutil. (x como T) .Lo que () comunica “Sé que no solo se puede convertir x en T, sino que, además, eso solo implica conversiones de referencia o de unboxing, y además, que x no es nulo”. Eso sí comunica información diferente de ((T) x) .Whatever (), y tal vez eso es lo que el autor del código pretende.

A menudo he visto referencias a este artículo engañoso como evidencia de que “como” es más rápido que el casting.

Uno de los aspectos más obvios y engañosos de este artículo es el gráfico, que no indica lo que se está midiendo: sospecho que mide los moldes fallidos (donde “como” es obviamente mucho más rápido ya que no se lanza ninguna excepción).

Si se toma el tiempo de 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 a la carga” de la palabra clave como en lugar de un elenco.

El elenco directo necesita un par de paréntesis más que la palabra clave as . Entonces, incluso en el caso de que esté 100% seguro de cuál es el tipo, se reduce el desorden visual.

De acuerdo en la excepción, sin embargo. Pero al menos para mí, la mayoría de los usos de se reducen para comprobar la null posterior, lo cual me parece mejor que detectar una excepción.

El 99% de las veces cuando uso “como” es cuando no estoy seguro de cuál es el tipo de objeto real

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

y no quiero ver excepciones de lanzamiento explícito ni hacer un lanzamiento dos veces, usando “es”:

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

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 C-like es bastante terrible, legibilidad. Me gustaría que C # adoptara la syntax Javascript de:

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

O define un operador to , el equivalente de lanzamiento de as :

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

A la gente le gusta mucho porque los hace sentir seguros de las excepciones … Como garantía en una caja. Un tipo pone una elegante garantía en la caja porque quiere que te sientas abrigado y caliente. Te imaginas que pones esa pequeña caja debajo de tu almohada por la noche, el Fairy Guarantee podría bajar y dejar un cuarto, ¿verdad, Ted?

Volviendo al tema … cuando se usa un lanzamiento directo, existe la posibilidad de una excepción de conversión no válida. Entonces la gente aplica as una solución global a todas sus necesidades de transmisión porque as (por sí mismo) nunca arrojará una excepción. Pero lo curioso de eso, es en el ejemplo que le diste (x as T).SomeMethod(); está intercambiando una excepción de conversión no válida para una excepción de referencia nula. Lo cual ofusca el problema real cuando ves la excepción.

Generalmente no uso demasiado. Prefiero la prueba de is porque, para mí, parece más legible y tiene más sentido que intentar un yeso y verificar null.

Este tiene que ser uno de mis principales problemas .

El D & E de Stroustrup y / o alguna publicación de blog que no encuentro ahora discute la noción de un operador to que abordaría el punto hecho por https://stackoverflow.com/users/73070/johannes-rossel (es decir, la misma syntax as pero con semántica DirectCast ).

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 puede usarlo.

Es una lástima que los progtwigdores ‘inteligentes’ (a menudo autores de libros (Juval Lowy IIRC)) den la vuelta a esto abusando de esta manera (C ++ no ofrece una, probablemente por esta razón).

Incluso VB tiene más consistencia en tener una syntax uniforme que te obliga a elegir un TryCast o DirectCast y tomar una decisión .

Creo que la palabra clave as podría considerarse una versión más elegante del dynamic_cast de C ++.

Probablemente sea más popular sin ninguna razón técnica, sino simplemente porque es más fácil de leer y más intuitivo. (No digo que lo hace mejor simplemente tratando de responder la pregunta)

Una razón para usar “como”:

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

En lugar de (código malo):

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