Функции отладки С#, содержащие лямбда-выражения

У меня есть функция с выражением лямбда:

int maxOccurrences = ( from field in data select field ).Max( f => f.Occurrences )

P.S. Я уверен, что есть более симпатичная/опрятная/более идиоматическая версия вышеупомянутого утверждения, было бы неплохо узнать, что это может быть, хотя это не важно для вопроса!

Если я изменяю что-то еще внутри функции, в то время как отладка говорит выражение Console.Write, отладчик утверждает:

Модификация "метода", которая содержит выражение лямбда, предотвратит продолжение сеанса отладки, пока разрешено редактирование и продолжение.

Мне было интересно, почему это может быть так?

Я бы подумал, что IL, сгенерированный для функции lamba и оператора Console.Write, будет отдельным и что Debugger может изменять и изменять, когда это необходимо. Есть ли какая-то фундаментальная концепция, которую я пропустил относительно функциональности lamda?

Ответы

Ответ 1

Дело не в том, что во всех случаях достичь невозможно (я не думаю). Однако это будет особенность монстра.

Когда у вас есть синтаксис LINQ в вашем методе, обычно это включает в себя какой-то анонимный метод или за кадром:

// This LINQ query...
var fields = from field in data select field;

// ...is equivalent to this:
var fields = data.Select(f => f);

... или просто выровняйте перед кулисами (как в вашем примере):

( from field in data select field ).Max( f => f.Occurrences ) // <- lambda

Анонимный метод, в свою очередь, скомпилируется в тип с методами экземпляра для поддержки кода, который вы написали.

В приведенном выше примере рассмотрим f => f.Occurrences лямбда. Это скомпилируется в тип с одним полем экземпляра, тип которого является локальным f в этой лямбда; этот тип содержит метод, который возвращает f.Occurrences.

Итак, когда код в конечном итоге перечисляет результат вашего запроса LINQ, происходит то, что экземпляр этого генерируемого компилятором типа создается для каждого field в data, и этот тип генерирует единственный метод, который был сгенерирован для поддержки выражения f => f.Occurrences lambda вызывается для вычисления Max.

Проблема с edit-and-continue заключается в том, что если какое-либо изменение в лямбда-выражениях в редактируемом методе, это требует изменения генерируемых типов, что не является вариантом. Можно было бы подумать, что это все равно можно сделать в случае, когда ничего не меняется относительно самих лямбда-выражений; пока одни и те же локали захвачены, а анонимные методы не изменяются, должно быть возможно модифицировать метод с этими характеристиками при отладке, как и для "обычных" методов в VS.

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

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

Ответ 3

Существует очень простой способ отладки выражения lamba. Преобразуйте его в анонимный метод, используя встроенный делегат. Просто.:)