Почему я не могу отредактировать метод, который содержит анонимный метод в отладчике? - PullRequest
14 голосов
/ 24 февраля 2009

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

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

Спасибо.

Ответы [ 4 ]

16 голосов
/ 24 февраля 2009

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

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

  1. Генерирует метаданные в виде класса
  2. Редактирует или генерирует универсальный метод

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

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

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

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

1 голос
/ 25 мая 2011

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

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

1 голос
/ 24 февраля 2009

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

0 голосов
/ 24 февраля 2009

Перезапуск модульного теста должен занять несколько секунд, если это так. Мне никогда не нравилась модель «редактировать и продолжать», если честно - вы всегда должны перезапускать IMO с нуля, на случай, если изменение в середине выполнения повлияет на код, который запускался ранее. Учитывая это, вам лучше использовать модульные тесты, которые можно запустить с очень быстрым оборотом. Если ваши индивидуальные юнит-тесты начинаются с невыносимого времени, вы должны обратить на это внимание.

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

...