Search code examples
c#casting

C# type casting isn't checked when a function takes a dynamic object as input parameter


I have a function that takes in a dynamic type object. The function does work to parse that object then returns back some information about what it parsed. For some weird reason when I take the returned object and store it into another variable, that new variable doesn't check to see that the object type matches at compile time.

I've reduced this problem as much as I can in the below example.

See here I have two functions called ReturnDouble() and they both return a value of type double the only difference between these functions is that one of them takes an input argument of type dynamic.

In the DoSomething() function I'm simply calling these two functions and storing their values into an int type variable. I'd have expected that BOTH of those calls would give a compilation error since you can't implicitly convert a double to an int, but weirdly enough the ReturnDouble(dynamic obj) function doesn't throw an error.

enter image description here

In this example I'm using double's and int's to keep it simple, but in my larger code I take that dynamic obj object and parse a lot of information out of it and pass back a larger class object.

public static double ReturnDouble()
{
    return 1.0;
}
public static double ReturnDouble(dynamic obj)
{
    // do some stuff with object 'obj'
    return 1.0;
}
public static void DoSomething()
{
    dynamic obj = new { };
    int forSomeReasonThisCompilesWithoutError = ReturnDouble(obj);
    int asExpectedThisCompilesWithErrors = ReturnDouble();
}

Solution

  • obj is a dynamic expression because it is of type dynamic.

    No compile time (static) binding is done for dynamic expressions. The overload resolution of ReturnDouble will therefore be done at runtime. This means that the compiler doesn't know what type ReturnDouble will return. You can think of ReturnDouble as also returning dynamic in this case.

    As a result, the = operator also isn't statically bound, and so the compiler doesn't check if the expressions on its two sides have the correct types.

    Instead, dynamic binding is done for them at runtime. That means your code int forSomeReasonThisCompilesWithoutError = ReturnDouble(obj); will throw an exception at runtime, rather than emit a compiler error.

    From the spec.

    ... However, if an expression is a dynamic expression (i.e., has the type dynamic) this indicates that any binding that it participates in should be based on its run-time type rather than the type it has at compile-time. The binding of such an operation is therefore deferred until the time where the operation is to be executed during the running of the program. This is referred to as dynamic binding.