2010-02-21 10 views
49

No es un comportamiento extraño con el uso dinámico de C# 4.0:¿Hay algún problema con la palabra clave dinámica en C# 4.0?

using System; 

class Program { 
    public void Baz() { Console.WriteLine("Baz1"); } 
    static void CallBaz(dynamic x) { x.Baz(); } 

    static void Main(string[] args) { 
    dynamic a = new Program(); 
    dynamic b = new { Baz = new Action(() => Console.WriteLine("Baz2")) }; 

    CallBaz(a); // ok 
    CallBaz(b); // ok 
    CallBaz(a); // Unhandled Exception: 
    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 
    // The name 'Baz' is bound to a method and cannot be used like a property 
    } 
} 

estoy usando el Visual Studio 2010 Release Candidate.

¿Esto es un error? Si es verdad, ¿se solucionará en la versión?

+6

Dónde está Eric Lippert: D –

+1

puedo reproducirlo también ... La primera llamada a CallBaz (a) funciona bien, la segunda llamada falla. Parece un error, y uno serio ... –

+2

Interesante.He dejado caer un correo electrónico en una lista apropiada, espero que reciba algo de atención pronto. –

Respuesta

32

Puedo confirmar que se trata de un error. La descripción rápida de lo que está pasando aquí es la siguiente: En CallBaz, hay un solo callsite que se invoca tres veces. Ese callsite es un InvokeMember, porque es la mejor suposición que puede hacer el compilador dada la sintaxis de C#, a pesar de que, en realidad, podría resolverse en un GetMember seguido de una Invoke.

Durante la segunda ejecución del callsite, este es sin duda el enlace que encuentra el tiempo de ejecución. Y entonces produce un aplazamiento a un GetMember seguido de una invocación. El error es que este aplazamiento no se restringe propiamente al caso donde el argumento es del tipo anónimo. Por lo tanto, en la tercera ejecución, se produce el aplazamiento y GetMember intenta vincularse al Programa, que por supuesto falla.

Gracias por encontrar esto. Como señala Eric, estamos en una etapa muy avanzada aquí, y se está volviendo difícil solucionar los problemas antes de enviarlos. Pero también queremos enviar el producto correcto. Voy a hacer lo que pueda para resolver esto, aunque es posible que no tenga éxito. Si se te ocurre algo más, no dudes en contactarme. =)

ACTUALIZACIÓN:

A pesar de que no puede garantizar que la versión final de VS 2010 y C# 4 se verá como cuando se lance, puedo decir que tuve éxito en empujar Esto soluciona a través. La versión de custodia de publicación de hoy se comporta correctamente para su código. A menos que ocurra alguna catástrofe, verás esto arreglado en el lanzamiento. Gracias de nuevo. Te debo una cerveza.

+2

¡Bien, gracias, Chris! – ControlFlow

+0

Guau, eso fue rápido ... bien hecho, ¡son muy buenas noticias! –

2

Lo mismo sucede para mí, le sugiero lo informe here.

8

Esto parece un grave error ...

Tenga en cuenta que funciona bien si se utiliza un ExpandoObject en lugar de un tipo anónimo:

using System; 
using System.Dynamic; 

class Program { 
    public void Baz() { Console.WriteLine("Baz1"); } 
    static void CallBaz(dynamic x) { x.Baz(); } 

    static void Main(string[] args) { 
    dynamic a = new Program(); 
    dynamic b = new ExpandoObject(); 
    b.Baz = new Action(() => Console.WriteLine("Baz2")); 

    CallBaz(a); // ok 
    CallBaz(b); // ok 
    CallBaz(a); // ok 
    } 
} 

tanto, la cuestión parece específica a los objetos anónimos ..

Aparentemente, en la segunda llamada al CallBaz(a), el DLR aún intenta acceder al Baz como una propiedad, porque era una propiedad del tipo anónimo. Sospecho que el C# ligante hace algo de almacenamiento en caché de resolución de la llamada para un mejor rendimiento, pero en ese caso es claramente roto ...

+1

Sí, creo que también, es un problema de almacenamiento en caché ... – ControlFlow

11

parece sospechoso. Lo enviaré a prueba y veremos qué dicen.

Sólo para fijar las expectativas: si esto es un error, y no se ha encontrado y ya fijado, más probable es una solución no va a entrar en la versión final.

¡Gracias por llamarnos así!

Cuestiones relacionadas