Как объединить DebuggerHidden с методами блока итераторов?

DebuggerHidden довольно удобен для маркировки вспомогательных методов, поэтому необработанные исключения останавливают отладчик в удобном месте:

К сожалению, это не похоже на работу с блоками итераторов:

(если это так, отладчик покажет in как текущий оператор во втором примере).

Хотя это, очевидно, является ограничением Visual Studio (для которого я представил отчет), есть ли какой-то способ, которым я мог бы обойти эту проблему, все еще используя блок итератора?

Я предполагаю, что это происходит потому, что сгенерированный компилятором код для реализации итератора не помечен [DebuggerHidden], Возможно, есть какой-то способ убедить компилятор сделать это?

1 ответ

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

Имейте вспомогательный класс, который разворачивает ваш итератор, а затем используйте метод расширения, чтобы задействовать обертку в вашем итераторе. Я обрабатываю исключения и перебрасываю. В VS2010 мне пришлось странным образом снять флажок опции "Включить только мой код", чтобы получить поведение, близкое к тому, что запрашивал OP. Если оставить этот параметр включенным, вы все равно попадете в реальный итератор, но ik выглядит слишком далеко.

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

Вспомогательный класс метода расширения:

public static class HiddenHelper
{
    public static HiddenEnumerator<T> Hide<T>(this IEnumerable<T> enu )
    {
        return HiddenEnumerator<T>.Enumerable(enu);
    }
}

Упаковочный:

public class HiddenEnumerator<T> : IEnumerable<T>, IEnumerator<T>
    {
        IEnumerator<T> _actual;
        private HiddenEnumerator(IEnumerable<T> enu)
        {
            _actual = enu.GetEnumerator();
        }

        public static HiddenEnumerator<T> Enumerable(IEnumerable<T> enu )
        {
            return new HiddenEnumerator<T>(enu);
        }

        public T Current
        {
            [DebuggerHidden]
            get 
            { 
                T someThing = default(T);
                try
                {
                   someThing = _actual.Current;
                }
                catch
                {
                   throw new Exception();
                }
                return someThing; 
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            _actual.Dispose();
        }

        object IEnumerator.Current
        {
            get { return _actual.Current; }
        }

        [DebuggerHidden]
        public bool MoveNext()
        {
                bool move = false;
                try
                {
                    move = _actual.MoveNext();
                }
                catch
                {
                     throw new IndexOutOfRangeException();
                }
               return move;
        }

        public void Reset()
        {
            _actual.Reset();
        }
   }

Использование:

        public IEnumerable<int> Power(int number, int exponent)
        {
            int counter = 0;
            int result = 1;
            while (counter++ < exponent)
            {
                if (result>Int16.MaxValue) throw new Exception();
                result = result * number;
                yield return result;
            }
        }

        public void UseIt()
        {
            foreach(var i in Power(Int32.MaxValue-1,5).Hide())
            {
                Debug.WriteLine(i);
            }
        }
Другие вопросы по тегам