parameter - initialize dynamic c#
Comportamiento impredecible en c#dynamic (2)
He encontrado un error (¿característica?) Durante el aprendizaje dinámico en C #. ¿Alguien puede explicarme, por qué tengo una excepción?
static class Program
{
public static void Main(string[] args)
{
dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));
var executer = someObj.Execute;
executer(); // shows "wtf"
someObj.Execute(); // throws RuntimeBinderException
Console.ReadKey();
}
static dynamic ConstructSomeObj(dynamic param)
=> new { Execute = param };
}
Nota: typeof exectuer y someObj es dinámico
Veamos el siguiente código:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");
// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();
// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();
}
}
dynamic
reflexión utiliza el método y los campos de los objetos y, dado que no puede conocer los tipos exactos, debe basarse en la información de tipo presente en los objetos en los que opera.
Cuando el campo x
en el tipo anónimo se escribe correctamente como invocación de delegado, foo.x()
funciona porque Dynamic puede ver que el valor del campo es delegado.
Cuando usas
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
para crear la clase anónima que creó la clase con el campo x
de tipo object
(dinámico es un object
detrás de escena). Cuando llama a obj.x
dynamic ve que el tipo de campo es un object
y no se molesta en verificar a qué tipo exacto apunta este campo. Y como el objeto no tiene el método Invoke()
como los delegados, lanza una excepción. Si cambia el tipo de parámetro del método a Action
, funcionará.
Supongo que esta decisión de comprobar el tipo de campo en lugar del tipo de valor que contiene el campo se tomó para proporcionar un mejor rendimiento. En otras palabras, cuando verifica el tipo de campo, la clase CallSite
generada por dynamic
se puede almacenar en caché y volver a usar más adelante.
EDITAR: Comprobado esto en mono, alguien puede verificar en VS
ok interesante Este 2 líneas funcionaría:
Task.Run(someObj.Execute);
((Action)someObj.Execute)();
Parece que el compilador acepta el () para tipos dinámicos siempre y en tiempo de ejecución, el CLR solo se ve "a un nivel de profundidad". Así que puedes ayudar aquí agregando el lanzamiento explícito o haciendo el lanzamiento implícito con el Task.Run (). Si esto es una característica o un error? ... ni idea ;-) ...