Подтвердить что ты не робот

Аномалия при использовании "var" и "dynamic"

Я столкнулся с проблемой аномалии, где в первый раз, используя ключевое слово var, меня немного.

Возьмите этот очень простой метод

public static Int32? GetNullableInt32(Int32 num)
{
    return new Nullable<Int32>(num);
}

Теперь мы можем вызвать этот метод с параметром dynamic, и все будет работать так, как ожидалось.

public static void WorksAsAdvertised()
{
    dynamic thisIsAnInt32 = 42;

    //Explicitly defined type (no problems)
    Int32? shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32);

    Console.Write(shouldBeNullableInt32.HasValue);
}

Однако, объявив shouldBeNullableInt32, используя неявное типирование, результаты далеки от того, что я ожидал бы.

public static void BlowsUpAtRuntime()
{
    dynamic thisIsAnInt32 = 42;

    //Now I'm a dynamic{int}... WTF!!!
    var shouldBeNullableInt32 = GetNullableInt32(thisIsAnInt32);

    //Throws a RuntimeBinderException
    Console.Write(shouldBeNullableInt32.HasValue);
}

Вместо Nullable<Int32> возвращаемое значение обрабатывается как динамический тип. И даже тогда базовый Nullable<T> не сохраняется. Так как System.Int32 не имеет свойства с именем HasValue, то бросается RuntimeBinderException.

Я был бы ОЧЕНЬ любопытным, чтобы услышать от кого-то, кто может фактически объяснить, что происходит (не просто догадаться).

Два вопроса

  • Почему shouldBeNullableInt32 получает неявно введенный в качестве динамического, когда возвращаемый тип GetNullableInt32 явно возвращает Nullable<Int32>?
  • Почему базовый Nullable<Int32> не сохраняется? Почему вместо dynamic{int}? (Ответ здесь: С# 4: Динамический и Nullable < gt;)

UPDATE

Оба ответ Рика Сладке и ответ Эрика Липперта в равной степени действительны. Прочитайте их оба:)

4b9b3361

Ответ 1

  • Почему shouldBeNullableInt32 получает неявно введенный в качестве динамического, когда возвращаемый тип GetNullableInt32 явно возвращает Nullable<Int32>?

Это потому, что, хотя нам очевидно, что GetNullableInt32 - это метод, который будет вызываться, из-за динамическое связывание, фактический метод, вызывающий вызов, откладывается до времени выполнения, потому что он вызывается с динамическим параметром. Может быть другая перегрузка GetNullableInt32, которая лучше соответствует значению времени выполнения thisIsAnInt32. Этот альтернативный метод, который не может быть известен до времени выполнения, может возвращать другой тип, чем Int32?!

В результате компилятор из-за динамической привязки вместо статической привязки не может предположить, что тип возврата выражения находится во время компиляции, и поэтому выражение возвращает тип dynamic. Это можно увидеть, наведя курсор на var.

Похоже, вы уже пришли к удовлетворительному объяснению своего второго вопроса:

Ответ 2

Ответ на Rick хорош, но просто для подведения итогов вы сталкиваетесь с последствиями двух основных принципов дизайна этой функции:

  • , если вы запрашиваете динамическую привязку, вы получаете динамическое связывание.
  • динамика - это просто объект, носящий забавную шляпу.

Первая проблема, которую вы идентифицируете, является следствием первого принципа проектирования. Вы просили проанализировать, что вызов будет отложен до выполнения. Компилятор сделал это. Это включает в себя отсрочку всего о вызове до времени выполнения, включая разрешение перегрузки и определение типа возврата. Тот факт, что у компилятора достаточно информации, чтобы угадать, что вы имели в виду, не имеет значения.

И если компилятор действительно догадывался о том, что вы имели в виду, то прямо сейчас вы задаете другой вопрос, а именно: "Я внес небольшое изменение в набор доступных методов, и вдруг компилятор изменил свой вывод тип для динамического, почему?" Это очень запутывает пользователей, когда поведение компилятора непредсказуемо.

(Все, что сказано, есть небольшое количество ситуаций, в которых компилятор скажет вам, что динамический код неверен. Бывают ситуации, когда мы знаем, что динамическое связывание всегда будет терпеть неудачу во время выполнения, и мы можем рассказать вам о их во время компиляции, а не ждать, пока ваш тестовый пример не сработает.)

Вторая проблема, которую вы идентифицируете, является следствием второго принципа проектирования. Поскольку динамика - это просто объект, носящий смешную шляпу, и потому, что поле nullables указывает либо на нулевую ссылку, либо на тип с нулевым значением в виде столбца, то нет такой вещи, как "динамическая нулевая".