..but it seems like the compiler is making a 'bad guess'. Can anyone explain this to me?
When you use dynamic
, the entire expression is treated at compile time as a dynamic expression, which causes the compiler to treat everything as dynamic and get run-time binding.
This is explained in 7.2 of the C# Language specification:
When no dynamic expressions are involved, C# defaults to static binding, which means that the compile-time types of constituent expressions are used in the selection process. However, when one of the constituent expressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound.
This basically means that most operations (the types are listed in section 7.2 of the spec) which have any element that is declared as dynamic
will be evaluated as dynamic
, and the result will be a dynamic
.
In your case, this statement:
var settings = new JavaScriptSerializer().Deserialize<dynamic>(json);
Uses dynamic, so, it getst reated as a dynamic expression. Since "Method invocation" is one of the C# operations subject to binding (7.2), the compiler treats this as dynamic bound, which causes this to evaluate to:
dynamic settings = new JavaScriptSerializer().Deserialize<dynamic>(json);
This, in turn, causes the DateTime.Parse
expressions to be dynamic bound, which in turn makes them return dynamic
.
Your "fix" works when you do DateTime startDate = DateTime.Parse(settings.startDate);
because this forces an implicit dynamic conversion (described in section 6.1.8 of the spec) of the result of the DateTime.Parse method to a DateTime:
An implicit dynamic conversion exists from an expression of type dynamic to any type T. The conversion is dynamically bound (§7.2.2), which means that an implicit conversion will be sought at run-time from the run-time type of the expression to T. If no conversion is found, a run-time exception is thrown.
In this case, the conversion is valid, so you effectively switch everything back to static binding from then on.