C# 3.0 introduced the implicit type "var". I've explained var as saying:
"I'm too lazy to tell you the type of this variable, so you figure it out, compiler."However, it's more useful than just promoting terseness or laziness:
1 2 | var i = 10; // implicitly typedint i = 10; //explicitly typed |
1 2 3 4 5 6 7 8 9 10 11 12 | / Example: var is required because// the select clause specifies an anonymous typevar custQuery = from cust in customers where cust.City == "Phoenix" select new { cust.Name, cust.Phone };// var must be used because each item // in the sequence is an anonymous typeforeach (var item in custQuery){ Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);} |
"There's no way for you or I to know the type of this now, compiler, so let's hope that the runtime figures it out."Here's how this looks from an Intellisense point of view. Here I'm hovering over the dynamic keyword:
And here is the tooltip after pressing "." after "calc."
Now, to the interesting question of the day. Christoff Turner asked this question, essentially:
"I noticed the following while doing some research within C# 4.0:"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System;namespace ConsoleApplication1{ class Program { static void f(Int32 x) { } static void f(dynamic x) {} static void f(Int32 x, dynamic y) {} static void f(dynamic x, Int32 y) {} static void f(Int32 x, dynamic y, Int32 z) {} static void f(dynamic x, Int32 y, dynamic z) {} static void Main(string[] args) { f(10); // Works - obvious f(10, 10); // Ambiguous - obvious f(10, 10, 10); // Ambiguous - not so obvious - since it should be possible to resolve } }} |
I stared it it a while longer, then realized what is happening, and called Mads Torgersen to confirm. Mads says this.
In short, the behavior is totally by design:
- dynamic in method signatures doesn’t come into it: it behaves like System.Object does.
- Given that, neither of the ternary signatures is better because each fits better than the other on some arguments (Int32 fits 10 better than object does)
The problem in the context of method calls is that you can't use the runtime type of something until, um, runtime. ;) Binding with dynamic expressions (dynamic binding) happens at runtime. In this case, we're compiling against method signatures that are known at compile type and we're compiling with a (mostly) static language, so there's no dynamic method dispatching happening that could select a different method overload at runtime.
The dynamic type is statically-typed as dynamic. The compile-time type is "dynamic" (but really it's object, hence the method overloading trouble.)
Another way to look at this is with Reflector. This C# code:
1 | static void f(Int32 x, dynamic y, Int32 z) {} |
1 | static void f(int x, [Dynamic] object y, int z) {} |
1 2 | [return: Dynamic]private static object GetCalculator() {} |
0 comments:
Post a Comment