【问题标题】:How to combine DebuggerHidden with iterator block methods?如何将 DebuggerHidden 与迭代器块方法结合使用?
【发布时间】:2012-06-18 20:47:26
【问题描述】:

DebuggerHidden 非常方便标记辅助方法,确保未处理的异常在方便的地方停止调试器:

             

不幸的是,这似乎不适用于迭代器块:

       

(如果是这样,调试器会将in 显示为第二个示例中的当前语句)。

虽然这显然是 Visual Studio 的一个限制(我已经 submitted a report),但有没有什么方法可以解决这个问题,同时仍然使用迭代器块?

我猜这是因为编译器生成的实现迭代器的代码没有用[DebuggerHidden] 标记。也许有一些方法可以说服编译器这样做?

【问题讨论】:

  • 我不太理解您以这种方式隐藏异常的设计决定。我可以看到可能发生的两种情况:1)您正在编写一个供其他开发人员使用的库。在这种情况下,它们没有您的源,并且在 VS 中,最低可见堆栈级别将是 ThrowIterator。所以这是你一开始想要的。 2) 此代码仅供您的团队在内部用于您的项目。在这种情况下,你为什么要让一个未捕获的异常就这样溜走而不去处理呢?万一它被抛出了,即使在调试的时候,你实际上也想看到它在 ThrowIterator 中,并且大多数 imp
  • 当然,我为什么使用这个功能并不重要。它就在那里,我只是想看看如何让它在所有情况下都能正常工作。
  • 但是如果你很好奇,可以考虑一个PerformQuery 方法,如果参数没有意义就会抛出。它仅供我们团队内部使用。该异常未被捕获,因为它是一个调试版本,专门避免捕获异常只是,以便 Visual Studio 在正确的位置停止。如果项目刚刚以通用的“出现问题”消息结束,那会不会只会使调试变得不必要地困难?我们知道有一个错误,还不如停在正确的行!
  • 那么这肯定是一个艰难的过程。不确定您是否可以利用迭代器生成的代码。很可能不会。

标签: c# visual-studio-2010 debugging visual-studio-debugging


【解决方案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);
            }
        }

【讨论】:

  • 似乎不像我在问题中描述的那样工作:(另外,无论有没有Hide,你的“用法”示例实际上都没有抛出。
  • 是的,它能够从一段已经执行的代码中挑选一个堆栈帧...开始试验/错误...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 2015-01-23
  • 2020-11-07
  • 2013-10-24
  • 2015-01-22
  • 1970-01-01
  • 2019-08-09
相关资源
最近更新 更多