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

Почему я не могу редактировать метод, содержащий анонимный метод в отладчике?

Итак, каждый раз, когда я писал выражение лямбда или анонимный метод внутри метода, который мне не совсем понятен, мне приходится перекомпилировать и перезагрузить все приложение или структуру unit test, чтобы исправить это. Это очень раздражает, и я в конечном итоге трачу больше времени, чем я спас, используя эти конструкции в первую очередь. Это так плохо, что я стараюсь держаться подальше от них, если могу, хотя Linq и lambdas относятся к моим любимым функциям С#.

Я полагаю, что есть хорошая техническая причина, почему это так, и, возможно, кто-то знает? Кроме того, кто-нибудь знает, будет ли он исправлен в VS2010?

Спасибо.

4b9b3361

Ответ 1

Да, есть очень веская причина, почему вы не можете этого сделать. Простая причина - это стоимость. Стоимость включения этой функции в С# (или VB) высока чрезвычайно.

Редактирование лямбда-функции - это конкретный случай класса вопросов ENC, которые очень трудно решить с текущей архитектурой ENC (Edit'n'Continue). А именно, очень сложно ENC любой метод, в котором ENC выполняет одно из следующих действий: -

  • Генерирует метаданные в виде класса
  • Редактирует или генерирует общий метод

Первая проблема связана скорее с логическим ограничением, но она также сталкивается с несколькими ограничениями в архитектуре ENC. А именно проблема создания первого класса не является ужасно трудной. То, что надоедливое, генерирует класс после второго редактирования. Двигатель ENC должен начать отслеживать таблицу символов не только для живого кода, но и для сгенерированных классов. Обычно это не так уж плохо, но это становится все труднее, когда форма сгенерированного класса основана на контексте, в котором он используется (как в случае с lambdas из-за закрытия). Что еще более важно, как вы решаете различия между экземплярами классов, которые уже живы в этом процессе?

Вторая проблема - строгое ограничение в архитектуре ENC CLR. Нет ничего, что С# (или VB) может сделать, чтобы обойти это.

Лямбдас, к сожалению, ударил по обоим этим вопросам. Короткий вариант заключается в том, что ENC'ing лямбда включает в себя множество мутаций на существующих классах (которые могут быть или не быть созданы из других ENC). Большая проблема заключается в устранении различий между новым кодом и существующими экземплярами закрытия, живущими в текущем пространстве процесса. Кроме того, лямбды, как правило, используют дженерики намного больше, чем другие коды, и попадают в проблему №2.

Детали довольно волосатые и немного слишком заняты для нормального ответа SO. Я подумывал написать длинный пост в блоге по этому вопросу. Если я подберусь к нему, я свяжу его с этим конкретным ответом.

Ответ 2

В соответствии со списком Поддерживаемые изменения кода вы не можете добавлять поля к существующим типам. Анонимные методы скомпилированы в классы с нечетным именем (kinda <>_c__DisplayClass1), которые являются именно такими: types. Несмотря на то, что ваши модификации анонимного метода могут не включать в себя изменение набора закрытых переменных (добавление этих параметров будет изменять поля существующего класса), я предполагаю, что причина невозможности изменения анонимных методов.

Ответ 3

Немного стыдно, что эта функция частично поддерживается в VB, но не в С#: http://msdn.microsoft.com/en-us/library/bb385795.aspx

Реализация такого же поведения в С# приведет к уменьшению уровня боли на 80% для функций, содержащих лямбда-выражения, где нам не нужно изменять лямбда-выражения или любое выражение, которое зависит от них, и, вероятно, не для "стоимости монстра" ".

Ответ 4

Перезапуск unit test должен занять несколько секунд. Мне никогда не нравилась модель "изменить и продолжить", если честно - вы всегда должны повторять с нуля ИМО, на всякий случай, если изменение в середине исполнения повлияло бы на код, который был раньше. Учитывая, что вам лучше использовать модульные тесты, которые можно запускать с очень быстрым поворотом. Если ваши индивидуальные тесты требуют невыносимого времени для запуска, это то, что вы должны посмотреть на адресацию.

EDIT: Что касается того, почему это не работает, вы можете обнаружить, что оно работает для некоторых лямбдов, но не для других. Лямбда-выражения, которые не захватывают никакие переменные (включая this), кэшируются в частной статической переменной, так что создается только один экземпляр делегата. Изменение кода означает повторную инициализацию этой переменной, которая может иметь интересные побочные эффекты, которые я подозреваю.