sábado, 6 de agosto de 2016

C# vs VB: TypeOf, typeof, GetType... Vaya lío

Cada vez que tengo que pasar código que maneja tipos de datos de C# a VB o viceversa tengo que consultar las equivalencias entre las diferentes instrucciones de los lenguajes: typeof, TypeOf, is, GetType... No sé porqué nunca consigo recordarlo.

Siempre pienso que debería escribir una entrada en el blog para ver si así acabo de retenerlo y, si no, al menos tener un sitio rápido donde puedo consultarlo. Como sé que no soy al único que le pasa me he decidido por fin a ponerlo por escrito.

Supongo que el origen del problema fue cuando el equipo de desarrollo de C# decidió crear el operador typeof sin tener en cuenta que en VB.NET ya existía un operador TypeOf  que realizaba una función diferente.

Por si esto fuera poco en VB.NET también existe el operador GetType, a la vez que en el Framework de .NET la clase Object define un método GetType, por supuesto que también con un comportamiento diferente.

Y no acaban hay los motivos para la confusión: en ambos lenguajes existe un operador is (is en C#, Is en VB.NET) y, por supuesto, también con un significado diferente.

Veamos pues cómo podemos realizar diferentes tareas en cada lenguaje:

Comprobar si un objeto es de un tipo dado
C# is vs VB TypeOf ... Is

Para comprobar si una variable es de un tipo dado en C# utilizaremos el operador is, mientras que en VB.NET utilizaremos el operador TypeOf...Is:


bool result = foo is string;
Dim result As Boolean = TypeOf foo Is String

Así las anteriores instrucciones comprueban si la variable foo es de tipo String.

Obtener el objeto System.Type de un tipo dado
C# typeof vs VB GetType

Para obtener el objeto System.Type de un tipo de datos utilizaremos el operador typeof en C# y el operador GetType en VB.NET:

Type systemType = typeof(string);
Dim systemType As Type = GetType(String)

Estas instrucciones obtienen el objeto System.Type del tipo String.




Obtener el objeto System.Type de una variable
El método Object.GetType

La forma de obtener el objeto System.Type de una variable sí que se realiza de la misma forma en C# y VB.NET porque para conseguirlo utilizaremos un método de la librería de .NET: el método Objetct.GetType:


Type fooType = foo.GetType();
Dim fooType As Type = foo.GetType()

El método GetType devolverá el objeto System.Type correspondiente al tipo de datos de la variable foo.

El operador Is de VB.NET

Pero habíamos dicho que VB.NET también tenía un operador Is y no hemos visto para que se utiliza. En realidad el motivo es que el operador Is en VB.NET no es un operador específico para tratar con tipos de datos, se trata de un operador para comparar variables de tipo objeto o por referencia.

En C# se utiliza el operador == indistintamente de si se trata de un tipo por valor o un tipo por referencia.


bool result = foo.GetType() == typeof(string);
Dim result As Boolean = foo.GetType() Is GetType(String)

Resumen

Por último el código de los 4 ejemplos que hemos visto con su resultado.

Espero haber ayudado a aclarar un poco el tema y que la próxima vez que tengas que tratar con tipos no tengas que recurrir a Google. Pero, por si acaso, añade esta entrada a los favoritos de tu navegador. Yo ya lo he hecho.


            var foo = "test string";

            bool result = foo is string;
            Console.WriteLine($"foo is string: {result}");
            // foo is string: True

            Type systemType = typeof(string);
            Console.WriteLine($"typeof(string): {systemType}");
            // typeof(string): System.String

            Type fooType = foo.GetType();
            Console.WriteLine($"foo.GetType(): {fooType}");
            // foo.GetType(): System.String

            result = foo.GetType() == typeof(string);
            Console.WriteLine($"foo.GetType() == typeof(string): {result}");
            // foo.GetType() == typeof(string): True
        Dim foo = "test string"

        Dim result As Boolean = TypeOf foo Is String
        Console.WriteLine($"TypeOf foo Is String: {result}")
        ' TypeOf foo Is String: True

        Dim systemType As Type = GetType(String)
        Console.WriteLine($"GetType(String): {systemType}")
        ' GetType(String): System.String

        Dim fooType As Type = foo.GetType()
        Console.WriteLine($"foo.GetType(): {fooType}")
        ' foo.GetType(): System.String

        result = foo.GetType() Is GetType(String)
        Console.WriteLine($"foo.GetType() Is GetType(String): {result}")
        ' foo.GetType() Is GetType(String): True



3 comentarios:

  1. Hola
    Una duda.
    No aprecio dónde está la diferencia entre:
    fo is string
    Y
    foo.GetType() == typeof(string)

    ResponderEliminar
  2. Hola Joseba,
    en realidad hay poca diferencia pero muy importante.

    foo.GetType() == typeof(string) comprueba que el tipo de la variable foo sea string, mientras que foo is string comprueba que el valor de la variable foo sea "compatible" con el tipo string, es decir, que la variable foo sea de tipo string o de un tipo derivado.

    Por ejemplo si establecemos la variable foo como:
    var foo = new ArgumentException();

    foo is Exception devolverá true, mientras que foo.GetType() == typeof(Exception) devolverá false.
    Sin embargo, tanto foo is ArgumentException como foo.GetType() == typeof(ArgumentException) devolverán true.

    ResponderEliminar