Let al seguente codice:
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
utilizza la reflection per accedere metodo di oggetti e campi e dal momento che non può conoscere i tipi esatti si deve fare affidamento su informazioni di tipo presente in oggetti su cui opera.
Quando il campo x
nel tipo anonimo è digitato correttamente come chiamata del delegato foo.x()
funziona perché dinamico può vedere che il valore del campo è delegato.
Quando si utilizza
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
per creare classe anonima si è creato classe con il campo x
di tipo object
(dinamica è object
dietro le quinte). Quando chiami dinamici obj.x
, quel tipo di campo è un object
e non si preoccupa di controllare a quale tipo esatto questo campo punta. E poiché l'oggetto non ha il metodo Invoke()
come delegato, genera un'eccezione. Se si modifica il tipo di parametro del metodo su Action
, funzionerà.
Suppongo che questa decisione di controllare il tipo di campo anziché il tipo di valore contenuto nel campo sia stata presa per fornire prestazioni migliori. In altre parole, quando si controlla la classe di tipo CallSite
generata da dynamic
, è possibile memorizzarla nella cache e riutilizzarla in seguito.
Riferimenti: 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
EDIT: Controllato questo su mono, qualcuno può verificare su VS
Qual è l'eccezione? Ed è tempo di compilazione o tempo di esecuzione? – RBarryYoung
Sembra che 'dynamic' generi codice per invocare il metodo quando vede' obj.foo() 'e genera il codice per accedere al campo quando vede' obj.foo'. Questo potrebbe essere un bug o almeno un comportamento inaspettato – csharpfolk
Probabilmente le informazioni sul tipo del metodo Execute su someObj non esiste in runtime, dal momento che lambda ha una parte di tipo anonimo e ha senso il contenuto di un tipo anon non pubblico. Vedi un problema simile su tipi dinamici anonimi: http://www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic –