Dynamically linking to an output type
In The C # Programming Language, Bill Wagner says:
Many people confuse dynamic bindig with output type. The output type is statically linked. The compiler determines the type at compile time. For example:
var i = 5; //i is an int (Compiler performs type inference) Console.WriteLine(i); //Static binding to Console.WriteLine(int)
The compiler says that i is an integer. All bindings to the variable I use static binding.
Now, given this information and my own dynamic dynamics:
dynamic i = 5; //Compiler punts
Console.WriteLine(i);//This is now dynamically bound
We know that type inference is statically linked. This means that a dynamic variable cannot use type inference to determine the type. How is a dynamic type resolved without using type inference?
Update
To try and clarify ... at runtime, we have to somehow figure out which type am I right? Since I am assigning a literal 5
, then the runtime can infer what i
is int
. Isn't this a type expression but dynamic binding?
source to share
How is Bill different?
The distinction Bill makes is that many people think that:
var x = Whatever();
x.Foo();
will work at runtime which method Foo to call based on the type of object returned at runtime by whatever. It is not true; it will be
dynamic x = Whatever();
x.Foo();
var
simply means "work out the type at compile time and replace it", not "work with it at runtime".
So, if I have
dynamic i = 5; Console.WriteLine(i);
What's happening?
The compiler generates code that morally looks like this:
object i = (object)5;
DynamicCallSite callSite = new DynamicCallSite(typeof(Console), "WriteLine"));
callSite.Invoke(i);
It's a little more complicated than this; the call site is cached, on the one hand. But it gives you a taste of it.
The invocation method queries i
for its type via GetType
, and then runs a special version of the C # compiler that can understand reflection objects. It performs overloading on Console
named members WriteLine
and determines which overload Console.WriteLine
would be called if i
injected as an int in the first place.
It then generates an expression tree representing this call, compiles the expression tree into a delegate, caches it in the invocation site, and invokes the delegate.
The second time you do this, the cached call site looks into its cache and sees that the last time i
an int was a specific delegate was called. So the second time it skips the call site creation and does overload resolution and just calls the delegate.
For more information see
http://ericlippert.com/2012/10/22/a-method-group-of-one/
http://ericlippert.com/2012/11/05/dynamic-contagion-part-one/
http://ericlippert.com/2012/11/09/dynamic-contagion-part-two/
For a historical perspective on this feature, check out Chris and Sam's blogs:
http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/
http://blogs.msdn.com/b/samng/archive/tags/dynamic/
They have done a lot to realize; however, some of these articles reflect outdated designs. Unfortunately, we never went with the "Phantom Method" algorithm. (Not a great algorithm, but a great name!)
source to share