Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit cast of dynamic method return value within a method doesn't allow an extension method to be called

Tags:

c#

dynamic

c#-4.0

The following code demonstrates my question:

public class DynamicExample
{
    public void DoSomething()
    {
        var x = new ExpandoObject();
        dynamic d = x;
        d.GetString = (Func<string>)(() => "Some Value");

        d.GetString().SomeStringExtension(); // Doesn't work - expected
        ((string)d.GetString()).SomeStringExtension(); // Works - expected
        Build(d).SomeStringExtension(); // Doesn't work - unexpected?
    }

    private static string Build(dynamic d)
    {
        return (string)d.GetString();
    }
}

public static class StringExtensions
{
    public static int SomeStringExtension(this string s)
    {
        return s.Length;
    }
}

The question is, why is there a difference for the compiler between casting the type inline to the extension method call and moving that cast out into a separate method?

like image 626
Josh Gallagher Avatar asked Oct 26 '11 11:10

Josh Gallagher


2 Answers

Build(d) is still a dynamic expression - the compile-time type of the method is dynamic even though you can see exactly what's going on. That means extension methods won't work.

Basically the compiler follows reasonably simple rules to determine what the type of an expression is, and almost any expression involving dynamic ends up being considered as a dynamic expression. The exceptions to this are:

  • d is SomeType (always considered to be bool)
  • Casts, both direct and using as

That's it as far as I can remember, although I could be mistaken...

Now the language could have been designed such that this case would statically resolve the call to Build as the only sensible one - after all, it's impossible for d to be of any type which would change which method is called - but to specify the exact rules for that would make the language specification (and the compiler) significantly more complicated for relatively little gain.

like image 83
Jon Skeet Avatar answered Nov 18 '22 23:11

Jon Skeet


If you hover over Build(d) in VS2010, you'll see that the entire expression is considered dynamic, and to be resolved at run-time. As such, it can't bind to the extension method (which would otherwise occur at compile-time.)

The reason the whole expression is dynamic is that without knowing the compile-time type of the argument, overload resolution can't be isn't performed, and so the return-type of the method can't be isn't known either.

like image 37
dlev Avatar answered Nov 18 '22 21:11

dlev