Josh Gallagher
Josh Gallagher

Reputation: 5329

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

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?

Upvotes: 5

Views: 597

Answers (2)

dlev
dlev

Reputation: 48596

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.

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500625

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.

Upvotes: 5

Related Questions