2010-02-21 17 views
49

C'è qualche strano comportamento con l'uso dinamico C# 4.0:C'è qualcosa di sbagliato nella parola chiave dinamica in 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 
    } 
} 

Sto utilizzando il Visual Studio 2010 Release Candidate.

È un bug? Se è vero, verrà risolto nella Release?

+6

Dov'è Eric Lippert: D –

+1

Posso anche riprodurlo ... La prima chiamata a CallBaz (a) funziona correttamente, la seconda chiamata fallisce. Sembra davvero un bug, e uno serio ... –

+2

Interessante.Ho lasciato cadere una e-mail in un elenco appropriato - si spera che prenda presto l'attenzione. –

risposta

32

Posso confermare che questo è davvero un bug. La breve descrizione di cosa sta andando storto qui è la seguente: In CallBaz, c'è un singolo callsite che viene invocato tre volte. Quel callsite è un InvokeMember, perché è la migliore ipotesi che il compilatore possa fare data la sintassi C#, nonostante possa, in realtà, risolversi in un GetMember seguito da un Invoke.

Durante la seconda esecuzione del callsite, si tratta in effetti del binding che il runtime trova. E quindi produce un rinvio a un GetMember seguito da un richiamo. Il bug è che questo differimento non si limita propriamente al caso in cui l'argomento è di tipo anonimo. Pertanto, nella terza esecuzione, il differimento entra in azione e il GetMember tenta di collegarsi al Programma, che ovviamente fallisce.

Grazie per aver trovato questo. Come sottolinea Eric, siamo in una fase molto avanzata qui, e sta diventando difficile risolvere i problemi prima della spedizione. Ma vogliamo anche spedire il prodotto giusto. Farò il possibile per risolvere il problema, anche se forse non ci riuscirò. Se ti viene in mente qualcos'altro, non esitare a contattarmi. =)

UPDATE:

Anche se posso fare alcuna garanzia ciò che la versione finale di VS 2010 e C# 4 sarà simile a quando le navi, posso dire che sono riuscito a spingere questa correzione attraverso. Il build di escrow di rilascio di oggi si comporta correttamente per il tuo codice. Salvo alcune catastrofi, lo vedrete risolto al momento del rilascio. Grazie ancora. Ti devo una birra.

+2

Bello, grazie, Chris! – ControlFlow

+0

Wow, è stato veloce ... ben fatto, questa è una buona notizia! –

2

La stessa cosa accade per me, suggerisco di segnalarlo here.

8

Questo appare come un grave bug ...

Nota che funziona bene se si utilizza un ExpandoObject invece di un tipo anonimo:

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 
    } 
} 

Quindi il problema sembra specifico per oggetti anonimi ..

Apparentemente, nella seconda chiamata a CallBaz(a), il DLR tenta ancora di accedere a Baz come proprietà, poiché si trattava di una proprietà di tipo anonimo. Sospetto che il raccoglitore C# faccia un po 'di cache per la risoluzione delle chiamate per prestazioni migliori, ma in tal caso è chiaramente rotto ...

+1

Sì, lo penso anch'io, è un problema di cache ... – ControlFlow

11

Sembra sospetto. Lo manderò a testare e vedremo cosa dicono.

Solo per impostare le aspettative: se questo è un bug, e non è stato ancora trovato e risolto, le probabilità sono buone, una correzione non entrerà nella versione finale.

Grazie per aver portato questo alla nostra attenzione!

Problemi correlati