Проблема с отладочными часами в Visual Studio с использованием методов перечисления доходности

У меня есть метод, который возвращает IEnumerable<>, который он создает с помощью синтаксиса yield return:

namespace Validation
{
    public class UserValidator
    {
        public IEnumerable<ValidationError> Validate(User user)
        {
            if (String.IsNullOrEmpty(user.Name))
            {
                yield return new ValidationError("Name", ValidationErrorType.Required);
            }

            [...]

            yield break;
        }
    }
}

Если я поставлю точку останова в методе, я могу перешагнуть через каждую строку, но если я попытаюсь использовать окна Watch или Immediate для просмотра значения переменной, я получаю эту ошибку:

Невозможно получить доступ к нестационарному члену внешний тип 'Validation.UserValidator.Validate' через вложенный тип 'Validation.UserValidator'

Кто-нибудь знает, почему это так и как я могу обойти это?

Ответ 1

ОК, просто попробовал, и я понимаю, что вы имеете в виду. Это больно! Я подозреваю, что это связано с закулисной работой, выполняемой компилятором (создание вложенных классов и т.д.) Для реализации возобновляемой логики машинного типа для yield. Один из способов обойти это (то, как я изначально пробовал ваш код) - сделать статический метод Validate, хотя, очевидно, это не очень удобно для дизайна.

Я думаю, причина, по которой сообщение об ошибке настолько тупое, является некоторой комбинацией:

  • Сгенерированные классы не существуют в вашем источнике, поэтому VS не имеет имен, с помощью которых можно ссылаться на них.
  • IIRC, имена, сгенерированные компилятором, содержат символы, недопустимые в идентификаторах С#, но действительные в базовой системе типа Framework.

У меня нет Reflector handy прямо сейчас, поэтому не могу подтвердить, но если вы чувствуете себя как пятно легкого мазохизма, подумайте о своей сборке и посмотрите на код, который компилятор пишет, чтобы мы просто смертные используют хороший синтаксический сахар, например yield return:). В Интернете есть много информации о том, как именно все это работает.

Изменить: после небольшого поиска, несколько лучших:
http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/
http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

Ответ 2

Метод не запускается до тех пор, пока вы не перечислите его.

var p = UserValidator.Validate(user).ToList();

Теперь вы можете отлаживать свой код.

Ответ 3

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

Это позволило мне найти ошибку, исправить ее. После исправления ошибки я вернул реализацию обратно к возврату доходности.

Болезненные.