【问题标题】:Why does the debugger hit the default case?为什么调试器会遇到默认情况?
【发布时间】:2020-05-01 01:00:28
【问题描述】:

某位同事遇到了一个非常奇怪的调试问题,他通过一个开关单步执行某些情况,但之后它也遇到了默认情况。我不知道这怎么可能发生!

它很容易重现,我终于将代码提取到一个小测试中。

如果我只在默认情况下设置断点,那么调试器将永远不会停在那里。但是如果我在 case 42 处添加断点,然后使用 step over,之后会遇到默认情况!! 请注意,尽管从未达到目标。所以似乎调试器正在显示一些实际上没有发生的事情? 另外,如果我删除异步任务并等待,那么它就不会发生.. 我们还需要另一个声明变量的案例(一些花哨的东西,而不是简单的整数等)

public class Foo
{
    public readonly string Bar = nameof(Bar);
}

public async Task DoSomething(int x)
{
    try
    {
       switch (x)
       {
            case 43:
                var foo = new Foo();
                break;     
            case 42:
                Console.WriteLine(x);
                break;
            default:
                throw new NotImplementedException("aaarghh..");
        }
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.Message);
    }
}

private async void btnSomethingTo_Click(object sender, EventArgs e)
{
    await DoSomething(42);
}

由 Sinatr 创建的 GIF 来说明手头的主题,谢谢!

【问题讨论】:

  • 您编译为 Debug 还是 Release? NotImplementedException 真的会被抛出吗?
  • 似乎调试器无法正确显示当前语句。
  • 您确定您的代码构建正确吗?也就是说,您可能正在调试一个旧的 exe,并且代码在构建后发生了变化?
  • 我相信这与调试模式下 switch 语句被编译为 if-else 语句(而不是发布模式下的跳转表)这一事实有某种关系。因此,不要在休息后击中最后一个花括号;声明它命中默认的最后一行。
  • 啊,不,我已经复制了这个。只有当DoSomething 方法是async 时才会发生这种情况。我认为调试器只是糊涂了。

标签: c# debugging switch-statement


【解决方案1】:

您没有以正确的方式使用 DoSomething 方法。 ASYNC 关键字意味着您在方法中的某处有一些 await 调用(以便稍后在任务结束后获取返回点),但您没有。 您奇怪的调试器行为与实现有关。您的异常不是事实引发的。我已经复制了您的案例,并且 MyException 构造函数只是被调试器忽略/跳过,并且也永远不会调用 catch (Exception exc) 部分中的代码。或者,如果我在 CASE 42: 中遇到了中断,并且我只是按 F5,那么我在 DEFAULT 部分中的断点将被跳过。

public async Task DoSomething(int x)
        {
            try
            {
                switch (x)
                {
                    case 43:
                        var foo = new Foo();
                        break;
                    case 42:
                        Debug.WriteLine(x);
                        break;
                    case 44:
                        break;
                    default:
                        throw new MyException("aaarghh..");
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            await DoSomething(42);
        }

        public class MyException : Exception
        {
            public MyException(string message): base(message)
            {
                if (message != null)
                    Debug.WriteLine(message);
            }

            public MyException() : base()
            {
            }

            public MyException(string message, Exception innerException) : base(message, innerException)
            {
            }
        }

【讨论】:

  • 好的,我可以在 DoSomething 中添加一个异步方法,但这与问题无关
  • 无论调试器如何步进,您的代码都具有正确的行为。在调试窗口中,您将只有“42”但没有“aaarghh..”
  • 即使我在await 里面DoSomething 我仍然会复制这个。是的,我认为这与调试器被为async 方法生成的代码混淆有关,但这与DoSomething 内部是否有await 无关。
  • 您说“您使用的 DoSomething 方法不正确”——我认为“不正确”与此无关,是我的观点
  • 重点是,我可以更新问题并在其中添加一个可等待的方法。那么行为仍然是相同的,并且您的答案不会增加任何新的见解。我已经发现代码实际上并没有执行。 (请参阅 OP“所以调试器似乎显示了一些实际上并没有发生的事情?”)
猜你喜欢
  • 2014-08-14
  • 1970-01-01
  • 2017-08-11
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
相关资源
最近更新 更多