Pregunta

Ya hay algunas publicaciones en el desbordamiento de la pila sobre este tipo de cosas, pero no son exactamente iguales, así que me disculpo de antemano si esto es algo que ya ha sido respondido.

Por qué esto no funciona:

public class MyBase { }

public class MyUtils
{
    public bool Foo<T> (T myObject) { return true; }
    public bool Foo (MyBase myBaseObject) { return false; }

    public void Go<T> (IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            // this test fails
            Assert.IsFalse (Foo (item));
        }
    }
}

Si llamo a Go() arriba y paso una carga de objetos MyBase, cada llamada a Foo llamará al Foo () genérico, que devuelve verdadero.

new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });      

¿Por qué no llama a la versión especializada MyBase?Si llamo a Foo (nuevo MyBase ()) directamente, infiere correctamente qué llamada realizar.¿Esto se debe a la falta de covarianza para las colecciones en C#3, o simplemente estoy siendo tonto y no lo hago correctamente?

¡Gracias!

isaac

¿Fue útil?

Solución

No llama al "especializado" porque el compilador elige qué método llamar cuando el programa (que en este caso es el Go función) es compilado, no cuando se ejecuta.

Cuando el compilador está compilando el Go función, la única información que tiene es que hay algún objeto de tipo T.No tiene idea de que en algún momento posterior le puedas proporcionar un objeto del tipo MyBase.La única opción que tiene es elegir el Foo<T> sobrecarga, por lo que lo integra en el programa compilado.

Si desea que una aplicación elija sobrecargas en tiempo de ejecución y elija la mejor sobrecarga mirando el objeto mientras la aplicación se está ejecutando, eso se llama "despacho dinámico" y solo lo usan lenguajes dinámicos como Ruby, Python, PHP. , etc.

C#3 es completamente estático y no admite esto.Tendrías que escribir una declaración if en tu código para verificar el tipo si quisieras que funcione de esta manera.C#4, por otro lado, tiene cierto soporte dinámico.Si estuviera escribiendo este código en C# 4, podría declarar la función 'Ir' de la siguiente manera:

 public void Go<T> (IEnumerable<dynamic> items)

Luego usaría el envío dinámico en tiempo de ejecución para elegir qué sobrecarga se llama y llamaría a la sobrecarga especializada para tomar MyBase

Otros consejos

Según C especificaciones # (7.4.3.2), el método no genérico es mejor que el genérico, por lo que debe ser seleccionado.

Sin embargo, creo que el genérico es recogido en su caso, ya que se llama dentro de un contexto invocación genérica (el "foreach" loop).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top