Lowder
Lowder

Reputation: 33

Using a dynamic variable as a method argument disables (some) compiler checks

Can someone explain to me why the compiler does not check the return type of a function if a dynamic variable is used as an argument to a method call?

class Program
{
    static void Main(string[] args)
    {
        // int a = GetAString(1); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'

        dynamic x = 1;

        int b = GetAString(x); // No compiler error -> Runtime Binder Exception 

        // int c = (string)GetAString(x); // Compiler error CS0029 Cannot impilicitly convert type 'string' to 'int'
    }

    static string GetAString(int uselessInt)
    {
        return "abc";
    }
}

Upvotes: 3

Views: 135

Answers (2)

Theodoros Chatzigiannakis
Theodoros Chatzigiannakis

Reputation: 29233

In the general case, the candidates aren't necessarily as straightforward as yours. For example, consider these two methods:

string M(string a) => a;
char[] M(char[] a) => a;     

What should this code suggest as the type of the last variable?

dynamic d = SomeExpression();
var s = M(d);

At this point, the designers of C# would have to make a choice:

  1. Assert that the return value of a method called with dynamic arguments is also dynamic itself.
  2. Select a type that can be assigned from all methods of the group (e.g. IEnumerable<char>).

The latter option is essentially what you're describing in your question. The C# designers went with the former option. Possible reasons for that design decision could be:

  • Maybe they thought that if you opt in to dynamic in an expression, then it's more likely than not that you'll want to keep using dynamic on any dependent expressions, until you explicitly opt out of it again.
  • Maybe they didn't introduce dynamic to enable multiple dispatch, so they didn't want to encourage it further by including provisions for static typing.
  • Maybe they thought that including those provisions would bloat the specification or make the language harder to understand.
  • Maybe the former option is simpler to implement (assuming you already have the rest of dynamic implemented) and they decided the other option wasn't worth more time or effort.
  • Maybe it's just not that straightforward to implement in C#. Value types could require boxing to match the common supertype, which complicates things. Raw pointer types are out of the unified hierarchy altogether.

Upvotes: 1

Sean
Sean

Reputation: 62542

By using dynamic the compiler will generate a call site anywhere you use a dynamic parameter. This call site will attempt to resolve the method at runtime, and if it cannot find a matching method will raise an exception.

In your example the call site examines x and sees that it is an int. It then looks for any methods called GetAString that take an int and finds your method and generates code to make the call.

Next, it will generate code to attempt to assign the return value to b. All of this is still done at runtime as the use of the dynamic variable has made the entire expression require runtime evaluation. The call site will see if it can generate code to assign a string to an int, and as it cannot it will raise an exception.

As an aside, your example doesn't make a lot of sense as you seem to want to assign a string to an int Your GetAsString method is even returning a non-numeric value so it's never going to assign to an int. If you write:

dynamic x = 1;
string b = GetAsString(x);

Then everything should work.

Upvotes: 2

Related Questions