是什么导致 Visual Studio 调试器停止评估 ToString 覆盖?

2024-01-10

环境:Visual Studio 2015 RTM。 (我没有尝试过旧版本。)

最近,我一直在调试我的一些野田时间 http://nodatime.org代码,我注意到当我有一个类型的局部变量时NodaTime.Instant(中央之一struct野田时间类型),“本地”和“观看”窗口似乎没有调用其ToString()覆盖。如果我打电话ToString()明确地在监视窗口中,我看到了适当的表示,但除此之外我只是看到:

variableName       {NodaTime.Instant}

这不是很有用。

如果我更改覆盖以返回常量字符串,则该字符串is显示在调试器中,因此它显然能够识别出它的存在 - 它只是不想在“正常”状态下使用它。

我决定在一个小演示应用程序中在本地重现此内容,这就是我的想法。 (请注意,在本文的早期版本中,DemoStruct是一个班级并且DemoClass根本不存在 - 我的错,但它解释了一些现在看起来很奇怪的评论......)

using System;
using System.Diagnostics;
using System.Threading;

public struct DemoStruct
{
    public string Name { get; }

    public DemoStruct(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        Thread.Sleep(1000); // Vary this to see different results
        return $"Struct: {Name}";
    }
}

public class DemoClass
{
    public string Name { get; }

    public DemoClass(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        Thread.Sleep(1000); // Vary this to see different results
        return $"Class: {Name}";
    }
}

public class Program
{
    static void Main()
    {
        var demoClass = new DemoClass("Foo");
        var demoStruct = new DemoStruct("Bar");
        Debugger.Break();
    }
}

在调试器中,我现在看到:

demoClass    {DemoClass}
demoStruct   {Struct: Bar}

但是,如果我减少Thread.Sleep从 1 秒调用到 900 毫秒,仍然有短暂的停顿,但随后我明白了Class: Foo作为值。时间长短似乎并不重要Thread.Sleep通话已接通DemoStruct.ToString(),它总是正确显示 - 并且调试器在睡眠完成之前显示该值。 (就好像Thread.Sleep被禁用。)

Now Instant.ToString()在 Noda Time 中做了相当多的工作,但它肯定不需要一整秒 - 所以大概有更多的条件导致调试器放弃评估ToString()称呼。当然,无论如何它都是一个结构体。

我尝试递归查看是否是堆栈限制,但情况似乎并非如此。

那么,我怎样才能找出是什么阻止了 VS 充分评估Instant.ToString()?如下所述,DebuggerDisplayAttribute看似有帮助,但不知道why,我永远不会对何时需要、何时不需要完全有信心。

Update

如果我使用DebuggerDisplayAttribute https://msdn.microsoft.com/en-us/library/system.diagnostics.debuggerdisplayattribute.debuggerdisplayattribute, 事情会改变的:

// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass

给我:

demoClass      Evaluation timed out

而当我在野田时间应用它时:

[DebuggerDisplay("{ToString()}")]
public struct Instant

一个简单的测试应用程序向我展示了正确的结果:

instant    "1970-01-01T00:00:00Z"

所以野田时间的问题大概是某个条件DebuggerDisplayAttribute does强制通过 - 即使它不强制通过超时。 (这符合我的预期Instant.ToString很容易足够快以避免超时。)

This may是一个足够好的解决方案 - 但我仍然想知道发生了什么,以及我是否可以更改代码以避免必须将属性放在 Noda Time 中的所有各种值类型上。

越来越好奇

无论是什么令人困惑,调试器有时只会混淆它。让我们创建一个类holds an Instant并将其用于自己的ToString() method:

using NodaTime;
using System.Diagnostics;

public class InstantWrapper
{
    private readonly Instant instant;

    public InstantWrapper(Instant instant)
    {
        this.instant = instant;
    }

    public override string ToString() => instant.ToString();
}

public class Program
{
    static void Main()
    {
        var instant = NodaConstants.UnixEpoch;
        var wrapper = new InstantWrapper(instant);

        Debugger.Break();
    }
}

现在我最终看到:

instant    {NodaTime.Instant}
wrapper    {1970-01-01T00:00:00Z}

然而,根据Eren在评论中的建议,如果我改变InstantWrapper作为一个结构体,我得到:

instant    {NodaTime.Instant}
wrapper    {InstantWrapper}

So it can评价Instant.ToString()- 只要被另一个调用ToString方法...在类中。根据所显示变量的类型,类/结构部分似乎很重要,而不是代码需要的内容 来执行以获得结果。

作为另一个例子,如果我们使用:

object boxed = NodaConstants.UnixEpoch;

...然后它工作正常,显示正确的值。让我感到困惑。


Update:

此错误已在 Visual Studio 2015 Update 2 中修复。如果您在使用 Update 2 或更高版本评估结构体值上的 ToString 时仍然遇到问题,请告诉我。

原答案:

您在使用 Visual Studio 2015 并在结构类型上调用 ToString 时遇到了已知的错误/设计限制。处理事情时也可以观察到这一点System.DateTimeSpan. System.DateTimeSpan.ToString()在 Visual Studio 2013 的评估窗口中工作,但在 2015 中并不总是工作。

如果您对底层细节感兴趣,请看以下内容:

评估ToString,调试器执行所谓的“功能评估”。简而言之,调试器挂起进程中除当前线程之外的所有线程,将当前线程的上下文更改为ToString函数,设置一个隐藏的保护断点,然后允许进程继续。当保护断点被击中时,调试器将进程恢复到之前的状态,并且函数的返回值用于填充窗口。

为了支持 lambda 表达式,我们必须在 Visual Studio 2015 中完全重写 CLR 表达式求值器。在较高级别上,实现是:

  1. Roslyn 为表达式/局部变量生成 MSIL 代码,以获取要在各个检查窗口中显示的值。
  2. 调试器解释 IL 以获得结果。
  3. 如果有任何“call”指令,调试器会执行 功能评估如上所述。
  4. 调试器/roslyn 获取此结果并将其格式化为 向用户显示的树状视图。

由于 IL 的执行,调试器总是处理“真实”和“假”值的复杂组合。真实值实际上存在于被调试的进程中。假值仅存在于调试器进程中。为了实现正确的结构体语义,调试器在将结构体值推送到 IL 堆栈时始终需要复制该值。复制的值不再是“真实”值,现在仅存在于调试器进程中。这意味着如果我们稍后需要执行函数评估ToString,我们不能,因为该值在流程中不存在。为了尝试获取值,我们需要模拟执行ToString方法。虽然我们可以模仿一些东西,但也有很多限制。例如,我们无法模拟本机代码,也无法执行对“真实”委托值的调用或对反射值的调用。

考虑到所有这些,以下是导致您看到的各种行为的原因:

  1. 调试器不评估NodaTime.Instant.ToString-> 这是 因为它是struct类型并且ToString的实现不能 由调试器模拟,如上所述。
  2. Thread.Sleep调用时似乎花费了零时间ToString在一个 struct -> 这是因为模拟器正在执行ToString。 Thread.Sleep 是一个本机方法,但模拟器是知道的 并忽略该呼叫。我们这样做是为了尝试获得价值 显示给用户。在这种情况下,延迟不会有任何帮助。
  3. DisplayAttibute("ToString()")作品。 -> 这很令人困惑。唯一的 隐式调用之间的区别ToString and DebuggerDisplay是隐式的任何超时ToString评估将禁用所有隐式ToString对此的评价 键入直到下一个调试会话。你可能会观察到 行为。

就设计问题/错误而言,这是我们计划在 Visual Studio 的未来版本中解决的问题。

希望事情能够澄清。如果您还有其他问题,请告诉我。 :-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是什么导致 Visual Studio 调试器停止评估 ToString 覆盖? 的相关文章

  • 通过 SocketCAN 进行 boost::asio

    我正在考虑利用升压阿西奥 http www boost org doc libs 1 49 0 doc html boost asio html从a读取数据套接字CAN http en wikipedia org wiki SocketCA
  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 在 C# 中按元素相乘数组具有意想不到的性能

    我想找到按元素相乘两个数组的最佳方法 这是更广泛项目的一部分 其中性能而不是唯一的考虑因素 我今天开始用 C Linqpad 编写一些函数 因此它还没有以任何方式进行优化 下面代码的输出如下 Environment ProcessorCou
  • 何时使用 =default 使析构函数默认?

    尽管对构造函数使用 default 对我来说很清楚 即强制编译器在其他构造函数存在时创建默认构造函数 但我仍然无法理解这两种类型的析构函数之间的区别 那些使用 default 的 那些没有显式定义并由编译器自动生成的 我唯一想到的是 gro
  • 使用 Enumerable.OfType() 或 LINQ 查找特定类型的所有子控件

    Existed MyControl1 Controls OfType
  • 如何在 C# / .NET 中创建内存泄漏[重复]

    这个问题在这里已经有答案了 可能的重复 托管代码中是否可能存在内存泄漏 特别是 C 3 0 https stackoverflow com questions 6436620 is it possible to have a memory
  • EF Core 通过完全替换断开集合导航属性的更新

    使用 EF Core 5 0 我有一个 SPA 页面 可以加载Group实体及其集合Employee来自 API 的实体 var groupToUpdate await context Groups Include g gt g Emplo
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • 找不到 assimp-vc140-mt.dll ASSIMP

    我已经从以下位置下载了 Assimp 项目http assimp sourceforge net main downloads html http assimp sourceforge net main downloads html Ass
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 将二进制数据从 C# 上传到 PHP

    我想将文件从 Windows C 应用程序上传到运行 PHP 的 Web 服务器 我知道 WebClient UploadFile 方法 但我希望能够分块上传文件 以便我可以监控进度并能够暂停 恢复 因此 我正在读取文件的一部分并使用 We
  • 如何在c的case语句中使用省略号?

    CASE expr no commas ELLIPSIS expr no commas 我在c的语法规则中看到了这样的规则 但是当我尝试重现它时 int test float i switch i case 1 3 printf hi 它失
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • C++ Streambuf 方法可以抛出异常吗?

    我正在尝试找到一种方法来获取读取或写入流的字符数 即使存在错误并且读 写结束时间较短 该方法也是可靠的 我正在做这样的事情 return stream rdbuf gt sputn buffer buffer size 但如果streamb
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • C++0x中disable_if在哪里?

    Boost 两者都有enable if and disable if 但 C 0x 似乎缺少后者 为什么它被排除在外 C 0x 中是否有元编程工具允许我构建disable if按照enable if 哦 我刚刚注意到std enable i
  • ASP.NET Core MVC 视图组件搜索路径

    在此处的文档中 https learn microsoft com en us aspnet core mvc views view components view aspnetcore 2 2 https learn microsoft

随机推荐

  • 我可以改进这个 JQuery 图像替换代码吗?

    HTML 看起来有点像 dl dt img src Something 1 dt dd Something 1 Text dd dl 此 HTML 重复 1 次或多次 因此同一页面上可能有许多 HTML 实例 我用来扩展 dd 并替换图像的
  • REST、HTTP DELETE 和参数

    向 HTTP DELETE 请求提供参数是否存在非 RESTful 的情况 我的场景是 我正在建模 您确定要删除它吗 设想 在某些情况下 资源的状态表明请求的删除可能无效 您可能可以自己想象一些需要确认删除的场景 我们采用的解决方案是向删除
  • 盐是否需要随机才能保护密码哈希?

    我对安全性知之甚少 我需要找到基础知识的基本解释 并且正在尝试想出一种合理的方法来使用 Net 将用户密码存储在数据库中 这是我当前的解决方案 private static byte HashPassword string password
  • 从 .Net 打印服务器端(不带 WinForms)

    嘿 印刷迷需要一些指导来引导我朝着正确的方向发展 我正在为当地一家商店开发一个 epos 系统 稍后我们将把它与一个电子商务网站结合起来 epos 系统的前端将是 WinForms 因此我们可以轻松处理 USB 设备 并且我们将使用 Web
  • 如何将常规 numpy 数组转换为记录数组?

    我读了一系列数字 np array f read split dtype np float64 然后我使用以下方法将其转换为二维数组np reshape 之后如何转换arr到记录数组 我尝试过 类似 以下操作 filename unstru
  • 使用 bash 脚本在 EC2 实例上启动会话管理器后如何在 EC2 实例上运行命令?

    我正在编写 bash 脚本来使用会话管理器在 ec2 实例上安装缺少的补丁 我可以使用脚本启动会话 但我不确定如何使用脚本在其上运行命令 instanceid i 098xxxx echo instanceid echo instance
  • Snowflake 身份验证令牌已过期 (390114) - Snowflake-SQLAlchemy 是否有心跳代码?

    我开发了一个 Flask 应用程序 使用 SQLAlchemy 连接到 Snowflake DB 作为后端 如果网站闲置时间超过 4 小时 我会遇到 Snowflake 身份验证令牌过期问题 我在谷歌上查了一下并找到了答案 https gi
  • jQueryUI 手风琴 - 每页可以有多个吗?

    我对 jQuery 很陌生 但已经找到了手风琴小部件并让它在大部分情况下都可以工作 我的问题是 一页上是否可以有多个手风琴 我有几个列表需要在视觉上分开 并且每个列表都需要是自己独立的手风琴 到目前为止 这是我的代码
  • Typescript 中动态导入模块的类型/类是什么?

    我在打字稿中查找导入模块的类型时遇到问题 有人可以帮助我吗 为了澄清我的问题我有一个模块module ts export class RSL1 然后我将其加载到我的index ts with const script await impor
  • 单击锚点时如何设置/存储 cookie

    我正在尝试使用 Cookie 以便引用单击的锚标记应用默认样式或特定样式 即使浏览器关闭 重新打开也是如此 因此 如果用户单击第二个链接 关闭或刷新浏览器并重新打开 则样式应仍处于活动状态 如果这是第一次 则应应用默认样式 这有点超出了我的
  • 如何测试 Greasemonkey 脚本,尤其是在网页的本地副本上?

    我有自己的 javascript 需要用 Greasemonkey 进行测试 我以前从未与 Greasemonkey 合作过 我如何测试脚本 我没有在万维网上测试它 我已经保存了目标页面 Firefox gt 将页面另存为 gt 网页 完成
  • 如何将条件必需属性放入类属性中以与 WEB API 一起使用?

    我只想放条件必需属性这是与WEB API Example public sealed class EmployeeModel Required public int CategoryId get set public string Emai
  • 有没有一种简单的方法可以将此文本解析为地图

    我收到以下服务的响应 如何将其解析为Map 我首先想到在空白处分割 但它不起作用 因为该值可能包含空格 例如看看的价值SA键入以下响应 我想到的一种选择是在空白处分割provided前面的字符是双引号 但不知道如何为此编写正则表达式 TX
  • 命名管道服务器,如何中断或超时等待客户端连接和传入数据

    我正在为 Windows 编写一个简单的命名管道服务器 调用 Windows API 在 Java 中使用 JNA 但这不相关 我试图找出如何避免服务器永远卡住等待客户端连接或来自客户端的数据 服务器代码执行以下操作 1 它通过调用创建管道
  • 如何使用 graphviz 绘制树图?

    我无法重现一个简单的例子 事情是这样的 import pandas as pd import numpy as np import sklearn as skl from sklearn import tree from sklearn c
  • 如何在android中实现自定义按钮的onkeydown事件

    我在布局中定义了一个按钮 我实现了 onclick 按钮 没有任何问题 但现在我需要知道我的按钮何时向下和向上 例如财务按钮的 onkeydown 事件 海关按钮有类似的东西吗 因为 onKeyDown int keyCode KeyEve
  • 帮助递归选择

    情况是这样的 我有两张桌子 用户 注册用户 网站 消息 他们之间发送的个人消息 消息表有这些列 只是重要的列 id 发件人 发送邮件的用户的 ID 信息 用户的接收者ID 消息已发送 reply to 这条消息的id 回复 可以为NULL
  • POM/JAR中出现的宏依赖

    我有一个使用宏的 scala 项目 它基本上遵循此处描述的确切方法 http www scala sbt org 0 12 4 docs Detailed Topics Macro Projects html http www scala
  • save() 后 Laravel 关系可用性

    我正在使用 Laravel 5 构建一个简单的时间跟踪应用程序 其中有两个 Laravel 模型 一个称为 User 一个称为 Week 这些关系非常简单 周 php public function user return this gt
  • 是什么导致 Visual Studio 调试器停止评估 ToString 覆盖?

    环境 Visual Studio 2015 RTM 我没有尝试过旧版本 最近 我一直在调试我的一些野田时间 http nodatime org代码 我注意到当我有一个类型的局部变量时NodaTime Instant 中央之一struct野田