Why does the compiler output var as dynamic instead of a specific type?

Given this short sample program:

static void Main(string[] args) { Console.WriteLine(Test("hello world")); } private static int Test(dynamic value) { var chars = Chars(value.ToString()); return chars.Count(); } private static IEnumerable<char> Chars(string str) { return str.Distinct(); } 

An exception will be thrown at startup, similar to:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''object' does not contain a definition for 'Count''

The compiler value chose dynamic as the preferred type of the chars variable.

Does it have a reason not to select IEnumerable<char> as a specific type, given that the dynamic method is not returned from the chars method? Just changing the type manually to IEnumerable<char> solves the problem, but I wonder why dynamic is the default value in this case?

Edit

I probably used an example that was more complex than necessary. It seems that the question asked here:

Anomaly when using "var" and "dynamic"

Provides a shorter example and some information on why it works the way it does.

https://blogs.msdn.microsoft.com/ericlippert/2012/11/05/dynamic-contagion-part-one/

Describes how the compiler processes dynamics.

+7
c #
source share
4 answers

Using dynamic all method calls are resolved at runtime. Therefore, he refuses to guess at compile time which method is actually called when you call Chars() , Count() or even ToString() . It can be anything, something returns. This is often called "dynamic infection."

For everything the compiler knows, somtimes value.ToString() will return MyRandomPOCOClass , and at runtime it will be able to dig up some overload, for example Tuple<int,String> Chars(MyRandomPOCOClass x) . Maybe next time value.ToString() will return int . All bets are made. dynamic turns C # into a scripting language.

Here is an example of dynamic runtime overload behavior ( here is the fiddle ):

 public static void Main() { dynamic x = "foo"; Test(x); x = 34; Test(x); } public static void Test(string s) { Console.WriteLine("String " + s); } public static void Test(int n) { Console.WriteLine("Int " + n); } 

Output:

 String foo Int 34 
+5
source share

With dynamic value , how value.ToString() compiler know that it returns value.ToString() ?

It has the same name as our familiar C # method, but it is different.

+2
source share

Since the parameter passed to Test () is dynamic, and this parameter is passed to Chars (). The dynamic method significantly limits run-time type checking for any statements that include dynamic types, and this is β€œviral,” in the sense that any statement that includes a dynamic variable can only produce a dynamic variable.

0
source share

When you use str.Distinct (), it returns an object of type System.Linq.Enumerable DistinctIterator char type chars in your variable under IEnumerable<char> . It does not have the Count method itself. This is an iterator that returns an internal value one by one. Pass it an IEnumerable<char> to get the score. You can iterate over IEnumerable and print the values ​​(for the loop below it works fine because it is an iterator), but the base return value from the set does not have the Count method, unless a variable of type iterator is added to the IEnumerable<char> . Otherwise, you can use str.Distinct (). ToList () and this will work just fine without casting.

 static void Main(string[] args) { Console.WriteLine(Test("hello world")); } private static int Test(dynamic value) { var chars = Chars(value.ToString()); //foreach (var c in chars) // Console.WriteLine(c); return ((IEnumerable<char>)chars).Count(); } private static IEnumerable<char> Chars(string str) { return str.Distinct(); } 
0
source share

All Articles