【问题标题】:How to prevent the debugger from calling some source code when paused?如何防止调试器在暂停时调用某些源代码?
【发布时间】:2015-09-14 22:21:05
【问题描述】:

在 Visual Studio 中,当应用程序在调试模式下停止时,您可以将鼠标悬停在对象/属性上以查看其中的内容。

当您使用调试器打开一个对象时,就像我对上图所做的那样,该属性会调用它的 Get 方法,作为调试器检索属性值以显示给用户的一种方式。

class Program
{
        static void Main(string[] args)
    {
        Foo foo = new Foo();

        foo.MyLock.EnterWriteLock();
        foo.Bar = 5.1;
        foo.MyLock.ExitWriteLock();

        // "I stop here and attempt to see what the value of Bar is via the debugger."
        foo.MyLock.EnterReadLock();
        Console.WriteLine(foo.Bar);
        foo.MyLock.ExitReadLock();
    }
}

class Foo
{
    private double bar;
    public double Bar 
    {
        get
        {
            Console.WriteLine(MyLock.IsReadLockHeld);
            Debug.Assert(MyLock.IsReadLockHeld, "Please enter the read lock before attempting to read this property.");
            return bar;
        }
        set
        {
            Debug.Assert(MyLock.IsWriteLockHeld, "Please enter the write lock before attempting to write this property.");
            bar = value;
        }
    }

    public ReaderWriterLockSlim MyLock { get; set; }

    public Foo()
    {
        MyLock = new ReaderWriterLockSlim();
    }
}

在我的应用程序中,我在 Get 访问器中添加了一个 Debug.Assert() 调用,以确保此示例中的 Foo 已被锁定。每当我的代码调用 Bar 时,foo 应该按照设计被锁定,但是当调试器尝试查看 bar 时,foo 不会被锁定,这意味着断言应该失败。

当调试器遇到一个失败的断言时,它有时会抑制断言弹出窗口,而有时它会按照正常的失败断言行为显示断言弹出窗口。据我所知,Assert 弹出窗口似乎在调试器查看 Bar 值的前 1-2 次被抑制,但每次在前 1-2 次之后,弹出窗口都允许显示。虽然这是断言抑制的最常见行为,但情况并非总是如此,因为在应用程序的其他运行中,无论调试器查看 Bar 多少次,调试器都不会停止抑制。

问题:对于我的应用程序,期望的行为是 100% 的时间抑制断言。我如何实现这一目标?

编辑: 此外,如果调试器命中其中一个断言并且它使以下消息失败,则它会帮助它写入调试输出。无论断言是否被抑制,这都是完全相同的消息。

---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
Please enter the read lock before attempting to read this property.
---- Assert Long Message ----

   at TestApp_Debugging.Foo.get_Bar() in c:\Users\Adrian.vanBerkhout\Documents\Visual Studio 2013\Projects\TestApp_Debugging\TestApp_Debugging\Program.cs:line 37
   at TestApp_Debugging.Program.Main(String[] args) in c:\Users\Adrian.vanBerkhout\Documents\Visual Studio 2013\Projects\TestApp_Debugging\TestApp_Debugging\Program.cs:line 17
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

【问题讨论】:

  • DebuggerDisplayAttribute 可能会帮助...或禁用 VS 中的属性评估...(我个人认为将 Assert 放入属性 getter 时会得到应得的:))
  • 我同意@AlexeiLevenkov - 比简单算术更复杂的代码应该是方法而不是属性。
  • @AlexeiLevenkov 即使在 Bar 属性上使用 DebuggerDisplay [DebuggerDisplay("myBar = {bar}")] 时,仍会调用断言。当我调试时,它会显示 DebuggerDisplay 消息。您知道为什么它可能仍在调用该属性吗?
  • @AlexeiLevenkov 你同意 Aasmund 我应该用方法替换我的所有属性吗?这肯定会解决断言问题,但失去属性的功能似乎很可惜。
  • @Adrian773 试图通过断言/异常来强制线程安全是很困难的(例如,您可以检查围绕“跨线程访问 UI 元素”有多少线程)。我会尝试重新设计 API 以避免完全 暴露 锁 - 即检查 ConcurrentQueue 作为示例。是的,这确实意味着没有属性,但是您可能能够设计出真正难以错误使用的界面(与当前需要精确排序 3 个方法/属性才能获得成功结果的界面不同。

标签: c# visual-studio-debugging


【解决方案1】:

我找到了解决方案here。使用DebuggerBrowsable 属性装饰您的问题属性。

[DebuggerBrowsable(DebuggerBrowsableState.Never)]

理想情况下,您永远不需要这样做。但是,我们有一些属性会在评估时(在调试中)触发代码协定异常,这会导致 Visual Studio 变得非常混乱。您可能需要装饰类上的属性和它实现的任何接口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    相关资源
    最近更新 更多