¿Por qué usar Linq's .Select () devuelve IEnumerable a pesar de que el tipo está claramente definido?

casting dapper dynamic linq

Pregunta

Estoy usando Dapper para devolver objetos dinámicos y, a veces, mapeándolos manualmente. Todo está funcionando bien, pero me preguntaba cuáles eran las leyes del casting y por qué los siguientes ejemplos son ciertos.

(para estos ejemplos usé 'StringBuilder' como mi tipo conocido, aunque generalmente es algo así como 'Producto')

Ejemplo 1: ¿Por qué esto devuelve un IEnumerable<dynamic> a pesar de que 'makeStringBuilder' devuelve claramente un objeto StringBuilder ?

Ejemplo 2: ¿Por qué esta compilación, pero 'Ejemplo 1' no lo haría si fuera IEnumerable<StringBuilder> ?

Ejemplo 3: ¿la misma pregunta que el ejemplo 2?

private void test()
    {
        List<dynamic> dynamicObjects = {Some list of dynamic objects};

        IEnumerable<dynamic> example1 = dynamicObjects.Select(s => makeStringBuilder(s));

        IEnumerable<StringBuilder> example2 = dynamicObjects.Select(s => (StringBuilder)makeStringBuilder(s));

        IEnumerable<StringBuilder> example3 = dynamicObjects.Select(s => makeStringBuilder(s)).Cast<StringBuilder>();

    }

    private StringBuilder makeStringBuilder(dynamic s)
    {
        return new StringBuilder(s);
    }

Con los ejemplos anteriores, ¿hay una forma recomendada de manejar esto? y el casting como este perjudica el rendimiento? ¡Gracias!

Respuesta aceptada

Cuando utiliza dynamic , incluso como parámetro, toda la expresión se maneja a través de enlace dinámico y dará como resultado ser "dinámico" en tiempo de compilación (ya que se basa en su tipo de tiempo de ejecución). Esto está cubierto en 7.2.2 de la especificación de C #:

Sin embargo, si una expresión es una expresión dinámica (es decir, tiene el tipo dinámico), esto indica que cualquier enlace en el que participe debe basarse en su tipo de tiempo de ejecución (es decir, el tipo real del objeto que denota en tiempo de ejecución) que el tipo que tiene en tiempo de compilación. Por lo tanto, la vinculación de dicha operación se difiere hasta el momento en que la operación debe ejecutarse durante la ejecución del programa. Esto se conoce como enlace dinámico.

En su caso, usar el molde lo convertirá con seguridad en un IEnumerable<StringBuilder> , y debería tener muy poco impacto en el rendimiento. La versión del example2 es ligeramente más eficiente que la versión del example3 , pero ambas tienen muy poca sobrecarga cuando se usan de esta manera.


Respuesta popular

Aunque no puedo hablar muy bien del "por qué", creo que debería poder escribir example1 como:

IEnumerable<StringBuilder> example1 = dynamicObjects.Select<dynamic, StringBuilder>(s => makeStringBuilder(s));

Necesitas decirle al compilador qué tipo de proyección debería tomar, aunque estoy seguro de que alguien más puede aclarar por qué no puede inferir el tipo correcto. Pero creo que al especificar el tipo de proyección, puede evitar tener que lanzar realmente, lo que debería generar algún beneficio en el rendimiento.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué