Alex Alex - 1 year ago 105
C# Question

Why does compiler infer var to be dynamic instead of concrete type?

Given this short example 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();
}


When run, it will produce an exception similar to:

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


Meaning compiler chose
dynamic
as a preferred type of
chars
variable.

Is there any reason for it not to choose
IEnumerable<char>
as a concrete type, considering dynamic is not returned from
Chars
method? Just changing the type manually to
IEnumerable<char>
solves the issue, but I'm wondering why is
dynamic
a default value in this case?

Edit

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

Anomaly when using 'var' and 'dynamic'

Provides more concise example and some insights as to why it works the way it does.

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

Describes how compiler handles dynamics.

Answer Source

With dynamic, all method calls are resolved at runtime. Therefore, it declines to guess at compile time what method is actually being called when you call Chars(), Count(), or even ToString(). It could be anything, returning anything. This is often called "dynamic contagion".

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

Here's an example of dynamic runtime overload behavior (here's a 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
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download