Passing dynamic object to C# method changes return type

I created a class that inherits DynamicObject and want to create a static method that can create new instances with pre-determined properties (stored in the Dictionary).

public class CustomDynamic : DynamicObject
{
    protected Dictionary<string, object> InnerDictionary;

    public static T Create<T>(Dictionary<string, object> dictionary) where T : CustomDynamic , new()
    {
        return new T
        {
            InnerDictionary = dictionary
        };
    }
}

Usage:

dynamic d = new Dictionary<string, object>();

var realPlayer = CustomDynamic.Create<Player>(d as Dictionary<string, object>);
var dynaPlayer = CustomDynamic.Create<Player>(d);

realPlayer // Player type according to VS2013
dynaPlayer // dynamic type according to VS2013

Since there is only one method signature, why does passing in a dynamic return a dynamic object? Or is actually just Visual Studio 2013 getting confused?


Solution 1:

This is because almost any operation involving a dynamic value is resolved dynamically at execution time. There are no exceptions made for cases where actually there's only one method present at compile-time; the language is simpler that way. (For certain calls, the compiler does perform enough resolution at compile-time to ensure that there is at least one method with a suitable number of parameters - this is specified in the C# 5 spec in section 7.5.4, but that doesn't affect the effective return type.)

From the C# 5 spec, section 7.6.5:

An invocation-expression is dynamically bound if at least one of the following holds:

  • The primary-expression has compile-time type dynamic.
  • At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.

In this case the compiler classifies the invocation-expression as a value of type dynamic. [...]

There are a few operations involving dynamic values which still have a non-dynamic overall type. For example:

  • d is Foo is always bool
  • d as Foo is always Foo
  • new Foo(d) is always Foo even though the exact constructor to use is determined at execution time

But any method call is treated as having a return type of dynamic.

Solution 2:

It's how dynamic works. From MSDN

Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic, or if the receiver of the method call is of type dynamic.

You might think that you don't have any additional overloads for your method but you might have. Compiler doesn't perform that check at compile time so that's why you see the type of dynaPlayer as dynamic instead of Player.