Pregunta ¿Operador de conversión directa frente a 'como'?


Considera el siguiente código:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

Cuál es la diferencia entre los tres tipos de casting (está bien, el tercero no es un casting, pero obtienes la intención). ¿Cuál debería ser el preferido?


578
2017-09-25 10:09


origen


Respuestas:


string s = (string)o; // 1

Lanzamientos InvalidCastException Si o no es un string. De lo contrario, asigna o a s, incluso si o es null.

string s = o as string; // 2

Asigna null a s Si o no es un string o si o es null. Por esta razón, no puede usarlo con tipos de valores (el operador nunca podría regresar) null en ese caso). De lo contrario, asigna o a s.

string s = o.ToString(); // 3

Causas Excepcion de referencia nula Si o es null. Asigna lo que sea o.ToString() vuelve a s, no importa de qué tipo o es.


Use 1 para la mayoría de las conversiones, es simple y directo. Tiendo a casi nunca usar 2 ya que si algo no es del tipo correcto, generalmente espero que ocurra una excepción. Solo he visto la necesidad de este tipo de funcionalidad con bibliotecas mal diseñadas que usan códigos de error (por ejemplo, return null = error, en lugar de usar excepciones).

3 no es un elenco y solo es una invocación a un método. Úselo para cuando necesite la representación de cadena de un objeto que no sea de cuerda.


694
2017-09-25 10:16



  1. Usar cuando algo debería seguro ser la otra cosa
  2. Úselo cuando algo puede ser el otro cosa.
  3. Úselo cuando no le importa qué es pero solo quieres usar el representación de cadena disponible.

285
2017-09-25 10:31



Realmente depende de si sabes si o es una cadena y lo que quieres hacer con ella. Si tu comentario significa que o realmente es una cuerda, preferiría la recta (string)o lanzar - es poco probable que falle.

La mayor ventaja de usar el reparto directo es que cuando falla, obtienes un InvalidCastException, que te dice más o menos lo que salió mal.

Con el as operador, si o no es una cadena, s se establece en null, que es útil si no está seguro y quiere probar s:

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

Sin embargo, si no realiza esa prueba, usará s más tarde y tener un Excepcion de referencia nula arrojado. Estos tienden a ser más comunes y mucho más difícil de rastrear una vez que salen en libertad, ya que casi cada línea desreferencia una variable y puede arrojar una. Por otro lado, si intentas convertir a un tipo de valor (cualquier primitiva, o estructuras como Fecha y hora), tienes que usar el reparto directo - el as no funcionará

En el caso especial de convertir a una cadena, cada objeto tiene una ToString, entonces su tercer método puede estar bien si o no es nulo y crees que ToString método puede hacer lo que quieras.


26
2017-09-25 10:16



Si ya sabes a qué tipo puede enviar, usa un molde de estilo C:

var o = (string) iKnowThisIsAString; 

Tenga en cuenta que solo con un molde de estilo C puede realizar coerción de tipo explícita.

Si no sabe si es del tipo deseado y lo va a usar si lo está, use como palabra clave:

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

Tenga en cuenta que como no llamará a ningún operador de conversión de tipo. Solo será no nulo si el objeto no es nulo y nativo del tipo especificado.

Utilice ToString () para obtener una representación en cadena legible para el ser humano de cualquier objeto, incluso si no se puede convertir en una cadena.


8
2017-09-25 10:41



La palabra clave as es buena en asp.net cuando usa el método FindControl.

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

Esto significa que puede operar en la variable tipeada en lugar de tener que lanzarla desde object como lo harías con un elenco directo:

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

No es algo enorme, pero ahorra líneas de código y asignación de variables, además es más legible


7
2017-09-25 11:17



'as' se basa en 'es', que es una palabra clave que verifica en tiempo de ejecución si el objeto es compatible polimórficamente (básicamente, si se puede hacer un molde) y devuelve nulo si falla la comprobación.

Estos dos son equivalentes:

Usando 'como':

string s = o as string;

Usando 'es':

if(o is string) 
    s = o;
else
    s = null;

Por el contrario, el elenco de estilo c se hace también en tiempo de ejecución, pero arroja una excepción si no se puede hacer el reparto.

Solo para agregar un hecho importante:

La palabra clave 'como' solo funciona con tipos de referencia. Tú no puedes hacer:

// I swear i is an int
int number = i as int;

En esos casos, debes usar el casting.


6
2017-09-25 10:15



2 es útil para lanzar a un tipo derivado.

Suponer un es un animal:

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

obtendrá un alimentado con un mínimo de moldes.


5
2017-09-25 10:31



"(cadena) o" dará como resultado una InvalidCastException ya que no hay conversión directa.

"o como cadena" dará como resultado que s sea una referencia nula, en lugar de una excepción lanzada.

"o.ToString ()" no es un elenco de ningún tipo per-se, es un método que se implementa por objeto, y por lo tanto de una manera u otra, por cada clase en .net que "hace algo" con la instancia de la clase a la que se llama y devuelve una cadena.

No olvide que para convertir a cadena, también hay Convert.ToString (someType instanceOfThatType) donde someType es uno de un conjunto de tipos, esencialmente los tipos base de frameworks.


4
2017-09-25 10:17