C# y sobrecarga de métodos genéricos… un detallito

A veces hay aspectos de C# que no pensamos hasta que nos encontramos con ellos… A mi me pasó con un código parecido a este:

class Program
{
    static void Main(string[] args)
    {
        Baz baz = new BazDerived();
        new Foo().Bar(baz);
        Console.ReadLine();
    }
}
class Foo
{
    public void Bar<T>(T t)
    {
        Console.WriteLine("Bar<T> typeof(T) = " + typeof(T).Name);
    }
    public void Bar(object o)
    {
        Console.WriteLine("Bar o.GetType() = " + o.GetType().Name);
    }
}
class Baz { }
class BazDerived : Baz { }

La pregunta seria: ¿cual es la salida por pantalla de este programa?

Pues… esta es la respuesta (para los que querais pensar un poco la he puesto en negro sobre negro… seleccionad el texto para verlo):

Bar<T> typeof(T) = Baz

La verdad es que tiene toda su lógica… lo que personalmente no me gusta nada es que este código compile sin generar ningún warning. ¿Que opinais vosotros?

Saludos!!!

4 comentarios sobre “C# y sobrecarga de métodos genéricos… un detallito”

  1. Hola Eduard!

    Muy interesante el post. Te paso algunos casos adicionales que estuve probando a partir de esto:

    * Si en Bar repetis la logica t.GetType() en lugar de typeof(T), devuelve BazDerived en lugar de Baz. Tiene bastante sentido, ya que al hacer typeof(T) estas preguntando el tipo de T asignado por el compilador. Y como no hay «polimorfismo de parametros», devuelve Baz.

    * Si la variable baz (de tipo BazDerived) la declaras como object en lugar de Baz, se invoca al metodo Bar, no parametrico. Es decir, sí va a haber algun caso en el que el metodo Bar se invoque. Me parece que por esto es que no es necesario levantar ninguna warning.

    Saludos!

  2. Holas, muy interesante el post, mi respuesta sería que no deberías usar typeof.
    Al igual que es preferible usar as en lugar de hacer (Tipo) var. En cuanto tienes un lenguaje que soporta polimorfismo lo mejor es dejar las decisiones sobre tipado para la ejecución, que es lo que te va a dar el comportamiento correcto. De cualquier forma, aunque C# te permite una sintaxis más simple para las llamadas a métodos genéricos, yo te recomiendo que hagas siempre las llamadas indicando el tipo, es decir, Bar(params) suele ser más coñazo de escribir, pero queda más claro para el que lo lee después. Aunque esto no soluciona el problema.

    Un saludo,
    Javier.

  3. Hola Santiago,
    muchas gracias por tus comentarios… 🙂

    Gracias por tus dos apuntes… terminan de explicar como resuelve el compilador el método a llamar.

    Lo del warning iba más en el sentido de que el compilador a veces nos avisa de cosas como un break que falta en un switch o demàs y también nos podría avisar de que hay una cierta ambigüedad entre el método Bar() y Bar()… Reconozco que no he pasado code analysis en este código, no se si alguna regla relacionada con esto saltaria. Porque viendo como funciona, este código parece un poco una mala práctica, no?

    Saludos!

  4. Hola Javier,
    Gracias por tus comentarios… 🙂

    Tienes toda la razón en lo que dices de usar GetType() en lugar de typeof() pero, teoricamente el método genérico, a diferencia del método «no genérico» estaba pensado para poder tratar nulls…
    Me explico: técnicamente el método genérico estaba pensado para usarse como tu comentas: Bar(null) lo que permitia saber que este «null» era de tipo «Tipo». Para el resto de casos se usaba el método «no genérico», haciendo simplemente Bar(xxx)… pero claro, esto fallaba cuando el compilador llamaba a Bar cuando usabas la sinaxis Bar(xxx) y nunca llamaba al método no genérico (salvo si xxx era de tipo object como apuntaba Santiago).

    Ya ves… cosas que uno se encuentra por ahí 😉

    Saludos!

Responder a anonymous Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *