Método de extensión y objeto dinámico

96

Voy a resumir mi problema en el siguiente fragmento de código.

List<int> list = new List<int>() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

El código anterior funciona bien.

Ahora probé lo siguiente

dynamic dList = list;
 Console.WriteLine(dList.First());

pero obtengo RuntimeBinderException. ¿Por qué es así?

santosh singh
fuente
Esto parece un duplicado de esta pregunta formulada hace solo 4 días stackoverflow.com/questions/5270782/…
jbtule
@jbtule La diferencia es que thisaquí es dinámico, pero si aterrizas aquí, probablemente también deberías mirar esa pregunta
nik.shornikov

Respuestas:

131

Para ampliar la respuesta de Stecya ... los métodos de extensión no son compatibles con la escritura dinámica en forma de métodos de extensión , es decir, llamados como si fueran métodos de instancia. Sin embargo, esto funcionará:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

Por supuesto, eso puede ser útil o no. Si pudiera brindar más información sobre por qué y cómo está tratando de utilizar la escritura dinámica, es posible que podamos ayudarlo más.

Jon Skeet
fuente
Estaba jugando con un objeto dinámico y obtuve esta excepción ¿Ha escrito algún artículo sobre este tema, dónde usar o no usar el objeto dinámico?
santosh singh
19
@geek: Personalmente, mi regla general es usar solo dynamicdonde realmente lo necesite ... básicamente, si de lo contrario accedería a los miembros con reflexión, esa es una gran señal. Por otro lado, soy un mecanografista estático empedernido; otros pueden sugerir políticas menos pesimistas :)
Jon Skeet
2
Podría ser más legible volver al tipo conocido, esto funciona: Console.WriteLine (((List <int>) dList) .First ()); O bien Console.WriteLine ((dList as List <int>) .First ()) ;.
AVee
138

Para ampliar la respuesta de Jon, la razón por la que esto no funciona es porque en los métodos de extensión de código no dinámicos normales funcionan haciendo una búsqueda completa de todas las clases conocidas por el compilador para una clase estática que tiene un método de extensión que coincide. La búsqueda va en orden según la anidación del espacio de nombres y la disponibilidadusing directivas en cada espacio de nombres.

Eso significa que para que una invocación de método de extensión dinámica se resuelva correctamente, de alguna manera el DLR tiene que saber en tiempo de ejecución cuáles usingeran todos los anidamientos y directivas del espacio de nombres en su código fuente . No tenemos un mecanismo útil para codificar toda esa información en el sitio de la llamada. Consideramos inventar un mecanismo de este tipo, pero decidimos que era un costo demasiado alto y generaba demasiado riesgo de programación para que valiera la pena.

Eric Lippert
fuente
Muchas gracias por la explicación.
santosh singh
3
¿Esta característica está a la vista? Sin duda, sería un cambio radical; las llamadas que actualmente arrojan RunTimeBinderExceptions comenzarían a funcionar repentinamente al volver a compilar la fuente. Además, ¿habría algún riesgo de seguridad asociado con la implementación de dicha función?
Ani
5
@ani: ¿Estamos planeando implementar esa función? No. ¿Existe algún riesgo de seguridad? No estoy enterada de nada; ¿Qué tipo de riesgo de seguridad tenía en mente? Empiece por decir quién es el atacante y qué amenaza le está haciendo al usuario.
Eric Lippert
@EricLippert, he entendido que todos los dynamicobjetos son iguales a C #:, DynamicObjectpor lo que no hay forma de diferenciarlos y es una de las razones por las que no es posible agregar métodos de extensión dynamic, ¿verdad?
Tom Sarduy
@EricLippert considera expandir esta respuesta un poco más y agregar una oración como "Cuando alguno de los parámetros es dinámico, entonces todas las resoluciones se aplazan hasta el tiempo de ejecución". Si bien es obvio para usted, esta parte importante es difícil de encontrar en cualquier otro lugar de SO (consulte stackoverflow.com/questions/48324768 por ejemplo)
Alexei Levenkov
18

Porque First()no es un método de List. Se define en Linq Extension paraIEnumerable<>

Stecya
fuente