type parameter initialize c# dynamic

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.

Referencias: https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs

https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpInvokeMemberBinder.cs

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 ;-) ...