2011-08-22 7 views
22

Mientras lee el código C# me encontré con un curioso fragmento:¿De qué sirve usar "es" seguido de "como" en lugar de "como" seguido de un cheque nulo en C#?

if(whatever is IDisposable) { 
    (whatever as IDisposable).Dispose(); 
} 

prefiero esperar que se está realizando ya sea como esto:

if(whatever is IDisposable) { //check 
    ((IDisposable)whatever).Dispose(); //cast - won't fail 
} 

o como esto:

IDisposable whateverDisposable = whatever as IDisposable; 
if(whateverDisposable != null) { 
    whateverDisposable.Dispose(); 
} 

Quiero decir as es como un yeso, pero devuelve null en caso de error. En el segundo fragmento, no puede fallar (ya que antes hay una verificación is).

¿Qué sentido tiene escribir código como en el primer fragmento en lugar de como en el segundo o en el tercero?

+0

Supongo que este último deja una variable en el ámbito, pero siempre lo hago de esa manera de todos modos. Creo que he leído un comentario de Jon Skeet recientemente que también prefiere el último caso. Aunque me sorprendería si no todos optimizaran hasta la misma cosa de todos modos. – Rup

+3

La tercera opción es la preferida, ya que solo tiene un 'as' /' is' y un cheque nulo; eso parece menos trabajo/menos sobrecarga que tener un 'es' primero y un' como' siguiente ... –

+0

He visto el último ejemplo en un libro, me parece más lógico también. – atoMerz

Respuesta

1

Para responder a su pregunta real: Experiencia y hábito.

Antes de la inclusión de la palabra clave as en .Net 2.0, la única forma de determinar con seguridad si un objeto se podía convertir a un tipo/interfaz específico era con la palabra clave is.

Por lo tanto, las personas adquieren el hábito de usar is antes de intentar una conversión explícita para evitar excepciones innecesarias. Esto llevó al patrón que tiene el segundo lugar en la lista de muestras:

if(whatever is IDisposable) //check 
{ 
    ((IDisposable)whatever).Dispose(); //cast - won't fail 
} 

Entonces, tenemos el seguro echado as palabra clave. Supongo que la mayoría de las personas, cuando empezaron a usar as, continuaron usando el patrón familiar, pero reemplazaron el yeso directo con un yeso seguro, y su patrón de elección se transformó en su ejemplo 1. (Sé que lo hice por . rato)

if(whatever is IDisposable) 
{ 
    (whatever as IDisposable).Dispose(); 
} 

con el tiempo, muchos o la mayoría o bien se dieron cuenta por sí mismos, o fueron instruidos por FXCop o CodeAnalysis que el patrón 'adecuado' es el ejemplo 3:

IDisposable whateverDisposable = whatever as IDisposable; 
if(whateverDisposable != null) 
{ 
    whateverDisposable.Dispose(); 
} 

es cierto que hay algunos flotando alrededor que todavía están en el ejemplo 1 etapa y todavía no han 'evolucionado' su patrón a su ejemplo 3 por alguna razón, u otros w Todavía usan el patrón de tiempo probado de is seguido de un lanzamiento directo.

1

Tiene razón, el primer código que publicó no es necesario. Utilice el segundo si desea que el alcance de la variable fundida esté dentro del if o use el tercero, si no importa, porque está haciendo la menor cantidad de trabajo.

3

no hay ningún punto de utilizar el as después de la is es cierto, sospecho que el código que lee el libro o sólo muestra cómo declarar y utilizar as y is. Lo usaría como usted sugiere en el segundo fragmento a través de:

IDisposable whateverDisposable = whatever as IDisposable; 
if(whateverDisposable != null) 
{ 
    whateverDisposable.Dispose(); 
} 

Tenga en cuenta también que, en su primer intento "((IDisposable)whatever)", que está lanzando el objeto que va a llevar el rendimiento "tiempo para lanzar", aquí se están emitiendo dos veces la primera vez usando as y el segundo usando el molde explícito, entonces la mejor manera es implementarlo usando el segundo método "as IDisposable y luego verificar si es null".

3

is seguido de as es una construcción sin sentido, como sospecha. En última instancia, si no está seguro de qué tipo es algo o qué interfaces implementa, hay dos expresiones idiomáticas, una para los tipos de referencia y otra para los tipos de valores.

Cuando se prueban los tipos de referencia (o un nulo encasillado), el último patrón que proporciona es el correcto - as seguido de una prueba nula. Este será el enfoque más rápido, ya que el tiempo de ejecución solo tendrá que realizar una prueba de tipo.

Al probar tipos de valores encuadrados, el segundo patrón que proporcione es el correcto: is seguido de un molde.

15

Usted está correcto. El primer fragmento no tiene sentido.

De las alternativas, recomendaría la tercera, ya que es segura para subprocesos en el sentido de que entre la comprobación y la llamada al método, el objeto no puede ser reemplazado por otro que no implementa la interfaz. Tenga en cuenta la situación siguiente con el segundo fragmento:

if (whatever is IDisposable) { //check 
    // <-- here, some other thread changes the value of whatever 
    ((IDisposable)whatever).Dispose(); // could fail 
} 

Esto no puede suceder con el tercer fragmento.

Nota: Hay some subtle differences entre un elenco y as con respecto a las conversiones definidas por el usuario, pero no se aplican en este caso.

+0

+1 para el escenario de multi-threading. –

+0

Es fácil hacer que el otro hilo sea seguro. 'x = lo que sea; if (x es IDisposable) {((IDisposable) x) .Dispose(); } ', aunque eso es un poco más detallado. –

+0

Entiendo que el fragmento 3 es "seguro para subprocesos" porque nada puede quitar o cambiar la referencia recién creada. Sin embargo, podría haber un cambio de hilo justo después de la comprobación nula que realiza algo con ese objeto a través de otra referencia, por lo que el objeto ya podría estar dispuesto, por ejemplo. ¿Puedes explicar a qué te refieres con hilo seguro? –

2

De acuerdo con el punto, pero si realmente lo que se vea limpia, ¿qué tal un método de extensión, como por ejemplo:

public static void DisposeIfNecessary(this object obj) 
{ 
    if (obj != null && obj is IDisposable) 
     ((IDisposable)obj).Dispose(); 
} 
1

Además, la última opción, obviamente, le da una variable dentro del alcance que pueda reutilizar más tarde sin tener que volver a invocar un elenco.

1

is seguido de as es inútil, más allá de ser más rápido de escribir (debido a las teclas necesarias para los corchetes y lo útil que es intellisense con as). Es marginalmente más lento que los otros dos ejemplos porque el tiempo de ejecución necesita hacer dos comprobaciones de tipo.

El CLR tiene algún truco para as, y como tal debe ser más rápido que el is seguido por el elenco (sin embargo, tenga en cuenta que no se puede utilizar con as tipos de valor).

Cuestiones relacionadas