Передача динамического объекта методу С# возвращает тип возврата

Я создал класс, который наследует DynamicObject и хочет создать статический метод, который может создавать новые экземпляры с заранее определенными свойствами (хранимыми в 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
        };
    }
}

Применение:

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

Поскольку существует только одна сигнатура метода, почему передача в динамическом возврате динамического объекта? Или на самом деле просто Visual Studio 2013 запутался?

Ответ 1

Это связано с тем, что почти любая операция, включающая динамическое значение, динамически решается во время выполнения. Исключений не существует для случаев, когда на момент компиляции присутствует только один метод; язык проще. (Для некоторых вызовов компилятор выполняет достаточное разрешение во время компиляции, чтобы гарантировать, что существует хотя бы один метод с подходящим количеством параметров - это указано в спецификации С# 5 в разделе 7.5.4, но это не влияют на эффективный тип возврата.)

Из спецификации С# 5, раздел 7.6.5:

Вызывающее выражение динамически связано, если выполняется хотя бы одно из следующих условий:

  • Первичное выражение имеет dynamic типа компиляции.
  • По крайней мере, один аргумент необязательного аргумента-списка имеет dynamic тип времени компиляции, а первичное выражение не имеет тип делегата.

В этом случае компилятор классифицирует выражение invocation как значение типа dynamic. [...]

Существует несколько операций с динамическими значениями, которые по-прежнему имеют нединамический общий тип. Например:

  • d is Foo всегда bool
  • d as Foo всегда Foo
  • new Foo(d) всегда Foo хотя точный конструктор для использования определяется во время выполнения

Но любой вызов метода обрабатывается как возвращаемый тип dynamic.

Ответ 2

Это динамично работает. Из MSDN

Разрешение перегрузки происходит во время выполнения, а не во время компиляции, если один или несколько аргументов в вызове метода имеют динамический тип или если получатель вызова метода имеет тип dynamic.

Вы можете подумать, что у вас нет дополнительных перегрузок для вашего метода, но у вас может быть. Компилятор не выполняет эту проверку во время компиляции, поэтому вы видите тип dynaPlayer как динамический, а не Player.