I (lazily) used var
in the original version of the below code and got a strange runtime exception in an entirely different part of the code. Changing "var" to "int" fixed the runtime exception but I cannot quite see why. I boiled the code down to this example;
public class Program
{
private static List<string> Test(string i) { return new List<string> {i}; }
private static dynamic GetD() { return 1; }
public static void Main()
{
int value1 = GetD(); // <-- int
var result1 = Test("Value " + value1);
// No problem, prints "Value 1", First() on List<string> works ok.
Console.WriteLine(result1.First());
var value2 = GetD(); // <-- var
var result2 = Test("Value " + value2);
// The below line gives RuntimeBinderException
// 'System.Collections.Generic.List<string>' does not contain a
// definition for 'First'
Console.WriteLine(result2.First());
}
}
I can see the type of the "var" being dynamic instead of int, but why does that type propagate to and affect the behaviour of the return value of the call to Test()
?
EDIT: Maybe I should clarify my question; I can see that dynamic
propagates to result2
, what I cannot understand is why, when the IDE clearly indicates that List<string> Test(string)
is the method called, it still infers the return value as dynamic. Is it a case of the IDE being more clever than the compiler?
Your code is compiled like this:
public static void Main()
{
int value1 = GetD(); // <-- int
List<string> result1 = Test("Value " + value1);
// No problem, prints "Value 1", First() on List<string> works ok.
Console.WriteLine(result1.First());
dynamic value2 = GetD(); // <-- var
dynamic result2 = Test("Value " + value2);
// The below line gives RuntimeBinderException
// 'System.Collections.Generic.List<string>' does not contain a
// definition for 'First'
Console.WriteLine(result2.First());
}
result2
is a dynamic object, then extention method is not supported on it (used as extention method).
However, you can do this:
Console.WriteLine(Enumerable.First(result2));
Your IDE is not so clever. Try to add the new method:
private static List<int> Test(int i) { return new List<int> { i }; }
It will propose you the two possibilities.
Paragraph 7.6.5 of the C# specification:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
- The primary-expression has compile-time type dynamic.
- At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With