Как объединить 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);
}
}