С# Динамическое ключевое слово - временная пенсия?

Определяет ли определение экземпляр как динамическое в С#:

  • Компилятор не выполняет проверку типа компиляции, но проверка времени выполнения выполняется так, как это всегда делается для всех экземпляров.

  • Компилятор не выполняет проверку типа времени компиляции, но выполняется проверка времени выполнения, в отличие от любых других нединамических экземпляров.

  • То же, что и 2, и это связано со снижением производительности (тривиальное? потенциально значимое?).

Ответ 1

Вопрос очень запутан.

Определяет ли определение экземпляр как динамическое в С#:

Под "определением экземпляра" вы имеете в виду "объявление переменной"?

Компилятор не выполняет проверку типа времени компиляции, но проверка времени выполнения выполняется так, как всегда, для всех экземпляров.

Что вы подразумеваете под "проверкой времени выполнения, как это всегда бывает"? Какую проверку времени выполнения вы имели в виду? Вы думаете о проверке, выполняемой верификатором IL, или вы думаете о проверках типов во время выполнения, вызванных кастами, или что?

Возможно, было бы лучше просто объяснить, что делает "динамический".

Во-первых, динамический с точки зрения компилятора типа. С точки зрения CLR нет такой вещи, как динамика; к моменту запуска кода все экземпляры "dynamic" были заменены "объектом" в сгенерированном коде.

Компилятор рассматривает выражения типа dynamic точно как выражения типа объекта, за исключением того, что все операции над значением этого выражения анализируются, компилируются и выполняются во время выполнения на основе типа среды выполнения экземпляра. Цель состоит в том, что исполняемый код имеет ту же семантику, что и компилятор знал во время компиляции типы выполнения.

Ваш вопрос, похоже, о производительности.

Лучший способ ответить на вопросы о производительности - попробовать и выяснить - что вам нужно делать, если вам нужны жесткие номера, - это написать код в обоих направлениях, используя динамические и использовать известные типы, а затем вытащить секундомер и сравнить таймингов. Это единственный способ узнать.

Однако рассмотрим влияние производительности некоторых операций на абстрактном уровне. Предположим, что у вас есть:

int x = 123;
int y = 456;
int z = x + y;

В настоящее время добавление двух целых чисел занимает около миллиардной доли секунды на большинстве аппаратных средств.

Что произойдет, если мы сделаем его динамическим?

dynamic x = 123;
dynamic y = 456;
dynamic z = x + y;

Теперь, что это делает во время выполнения? Это ячейки 123 и 456 в объекты, которые выделяют память в куче и делают некоторые копии.

Затем он запускает DLR и запрашивает DLR "имеет ли этот сайт кода скомпилирован один раз уже с типами для x и y, являющимися int и int?"

Ответ в этом случае - нет. Затем DLR запускает специальную версию компилятора С#, которая анализирует выражение сложения, выполняет разрешение перегрузки и выплескивает дерево выражений, описывающее лямбду, которая объединяет два ints. Затем DLR компилирует этот лямбда в динамически генерируемый IL, который затем компилирует jit-компилятор. DLR затем кэширует это скомпилированное состояние, так что во второй раз, когда вы спрашиваете, компилятор не должен делать все, что работает снова.

Это занимает больше времени, чем наносекунда. Он занимает потенциально много тысяч наносекунд.

Отвечает ли это на ваши вопросы? Я не совсем понимаю, что вы здесь задаете, но я думаю, что лучше всего.

Ответ 2

Насколько я знаю, ответ 3.

Вы можете сделать это:

dynamic x = GetMysteriousObject();
x.DoLaundry();

Поскольку компилятор не проверяет тип на x, он скомпилирует этот код, предполагая, что вы знаете, что делаете.

Но это означает, что должна выполняться дополнительная проверка времени выполнения: а именно, изучение типа x, если у него есть метод DoLaundry, который не принимает никаких аргументов и выполняет его.

Другими словами, вышеприведенный код похож на это (я не говорю то же самое, просто рисую сравнение):

object x = GetMysteriousObject();

MethodInfo doLaundry = x.GetType().GetMethod(
    "DoLaundry",
    BindingFlags.Instance | BindingFlags.Public
);

doLaundry.Invoke(x, null);

Это определенно не тривиально, хотя это не означает, что вы сможете увидеть проблему с невооруженным глазом.

Я полагаю, что реализация dynamic включает в себя довольно красивое скрытое кэширование, которое выполняется для вас, так что, если вы снова запустите этот код и x будет одного и того же типа, он будет работать много быстрее.

Не держите меня за это. У меня не так много опыта с dynamic; это просто то, как я понимаю это, чтобы работать.

Ответ 3

Объявление переменной как динамическое похоже на объявление объекта. Динамический просто получает еще один флаг, указывающий, что разрешение члена откладывается до времени выполнения.

В отношении штрафа за производительность - это зависит от того, что является базовым объектом. Что справедливо для всего объекта динамических объектов? Основной объект может быть объектом Ruby или Python или может быть объектом С#. DLR будет определять во время выполнения, как разрешать вызовы участников по этому объекту, и этот метод разрешения определяет ограничение производительности.

Сказав это - определенно есть штраф за производительность.

Вот почему мы не просто собираемся использовать динамические объекты повсюду.

Ответ 4

Ну, переменная статически типизирована как тип dynamic, но помимо этого компилятор не проверяет, насколько я знаю.

Связывание типов выполняется во время выполнения и да, есть штраф, но если dynamic - единственный вариант, то что. Если вы можете решить проблему, используя статическую типизацию, сделайте это. При этом DLR действительно вызывает кеширование сайта, что означает, что некоторые из накладных расходов уменьшаются, поскольку в некоторых случаях сантехника может быть повторно использована.

Ответ 5

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