是什么导致 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 覆盖? 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • BASIC 中的 C 语言中的 PeekInt、PokeInt、Peek、Poke 等效项

    我想知道该命令的等效项是什么Peek and Poke 基本和其他变体 用 C 语言 类似PeekInt PokeInt 整数 涉及内存条的东西 我知道在 C 语言中有很多方法可以做到这一点 我正在尝试将基本程序移植到 C 语言 这只是使用
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐

  • 我可以改进这个 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野田