Visual Studio 2015 中的断点配置和新的错误列表






4.62/5 (9投票s)
本文介绍了 Visual Studio 2015 在调试方面所做的改进。
引言
Visual Studio 始终是用于代码调试的优秀 IDE。它提供了许多用于调试和配置代码的功能。作为开发人员,我们总是花费大量时间运行和调试代码,因此调试功能的改进可以极大地提高我们的生产力。本文介绍了 Visual Studio 2015 在调试方面所做的改进。以下是本文将涵盖的一些主要功能:
- 断点配置改进
- 全新改进的错误列表
- 对 LINQ 和 Lambda 表达式的工具窗口支持
- 在代码编辑器中显示执行时间的新 PerfTips
- 新的诊断工具窗口
学习 Visual Studio 2015 系列
- 第 1 天:Visual Studio 2015 中的代码辅助
- 第 2 天:Visual Studio 2015 中的代码分析器
- 第 3 天:Visual Studio 2015 中的重命名辅助
- 第 4 天:Visual Studio 2015 中的代码重构
- 第 5 天:Visual Studio 2015 中的调试改进(断点配置和新错误列表)
- 第 6 天:Visual Studio 2015 中的调试改进(LINQ 和 Lambda 的工具窗口支持、PerfTips、诊断工具窗口)
断点配置改进
Visual Studio 的早期版本已经提供了断点配置功能,因此这对开发人员来说并不陌生。Visual Studio 2015 中唯一的新功能是用户体验和使用配置的便捷性。断点配置现在更易于使用和访问。Visual Studio 2015 引入了一个新的内联工具栏。通过此工具栏,您可以轻松打开断点配置设置或启用/禁用断点。其次,Visual Studio 2015 中断点配置的上下文菜单得到了简化。上下文菜单中的一些选项已移至断点配置设置窗口。设置窗口现在以“窥视”窗口的形式出现,因此您可以轻松检查和更改设置,因为不再有模式窗口。整个断点配置现在分为两个部分:操作和条件。让我们通过实际实现来详细了解该主题。我正在使用 Visual Studio 2015 企业版来撰写本文,并在我的 Visual Studio 中添加了一个名为 VS2015ConsoleApplication 的控制台应用程序。假设我们有一个 MyProduct
类,其中包含产品作为实体特定的基本操作,例如获取产品、返回产品列表,如下所示。
1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6: 7: namespace VS2015ConsoleApplication 8: { 9: public class MyProducts :IProducts 10: { 11: List<Product> _allProduct = new List<Product>(); 12: public MyProducts() 13: { 14: _allProduct.Add(new Product {ProductCode="0001",ProductName="IPhone",ProductPrice="60000",ProductType="Phone",ProductDescription="Apple IPhone" } ); 15: _allProduct.Add(new Product { ProductCode = "0002", ProductName = "Canvas", ProductPrice = "20000", ProductType = "Phone", ProductDescription = "Micromax phone" }); 16: _allProduct.Add(new Product { ProductCode = "0003", ProductName = "IPad", ProductPrice = "30000", ProductType = "Tab", ProductDescription = "Apple IPad" }); 17: _allProduct.Add(new Product { ProductCode = "0004", ProductName = "Nexus", ProductPrice = "30000", ProductType = "Phone", ProductDescription = "Google Phone" }); 18: _allProduct.Add(new Product { ProductCode = "0005", ProductName = "S6", ProductPrice = "40000", ProductType = "Phone", ProductDescription = "Samsung phone" }); 19: 20: } 21: 22: /// <summary> 23: /// FetchProduct having price greater that 3000 24: /// </summary> 25: /// <returns></returns> 26: public List<Product> FetchProduct() => (from p in _allProduct where Convert.ToInt32(p.ProductPrice) > 30000 select p).ToList(); 27: 28: /// <summary> 29: /// FetchProduct 30: /// </summary> 31: /// <param name="pCode"></param> 32: /// <returns></returns> 33: public Product FetchProduct(string pCode) 34: { 35: return _allProduct.Find(p => p.ProductCode == pCode); 36: } 37: 38: /// <summary> 39: /// FetchProduct with productCode and productName 40: /// </summary> 41: /// <param name="productCode"></param> 42: /// <param name="productName"></param> 43: /// <returns></returns> 44: public Product FetchProduct(string productCode, string productName) 45: { 46: return _allProduct.Find(p => p.ProductCode == productCode && p.ProductName==productName); 47: } 48: 49: public List<Product> GetProductList() 50: { 51: return _allProduct; 52: } 53: } 54: }
其中 IProducts
是一个简单的接口。
1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6: 7: namespace VS2015ConsoleApplication 8: { 9: interface IProducts 10: { 11: Product FetchProduct(string productCode); 12: Product FetchProduct(string productCode,string productName); 13: List<Product> GetProductList(); 14: } 15: }
在下面的 Program 类中,我们只是获取所有产品并为名为 ProductCodeWithPrice
的新实体创建一个新的产品列表,其中我们只列出产品的产品代码和价格。
1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: using System.Threading.Tasks; 6: 7: namespace VS2015ConsoleApplication 8: { 9: public class ProductCodeWithPrice 10: { 11: public string ProductCode { get; set; } 12: public string ProductPrice { get; set; } 13: 14: } 15: class Program 16: { 17: static void Main() 18: { 19: var myProducts = new MyProducts(); 20: var products = new List<ProductCodeWithPrice>(); 21: var allProducts = myProducts.GetProductList(); 22: foreach (var product in allProducts ) 23: { 24: ProductCodeWithPrice prod = new ProductCodeWithPrice(); 25: prod.ProductCode = product.ProductCode; 26: prod.ProductPrice = product.ProductPrice; 27: products.Add(prod); 28: } 29: Console.ReadLine(); 30: } 31: } 32: }
现在,假设我们正在调试代码,同时创建了一个新的产品列表,并且我们希望在 foreach 循环中创建新的 ProductCodePrice
实例之后放置一个断点。
当在第 27 行设置断点时,请注意新的内联工具栏。从这里我可以打开设置或启用和禁用断点。当我们右键单击断点以打开上下文菜单时,我们看到一个新的简化上下文菜单,其中大部分以前存在的选项现在已移至设置选项。
让我们再次检查内联工具栏。我们选择“设置”选项。请注意,设置现在以“窥视”窗口的形式出现,而不是模式对话框窗口。这有助于开发人员在调试时轻松修改设置。
条件
让我们尝试探索条件是如何工作的。当我们设置断点并打开设置窗口时,它会显示“条件”和“操作”选项,并提及断点的位置以及文件名、行号和字符位置等详细信息。单击条件复选框会显示其他一些有关如何配置条件的选项。
默认是“条件表达式”,但还有另外两个选项,即“命中计数”和“筛选器”。当需要在循环中的特定迭代处暂停执行时,可以使用“命中计数”选项。
第二个下拉列表用于验证条件。在这种情况下,我们在每次迭代中创建 prod 对象后放置了一个断点。
请注意,我们可以选择“是倍数”或“大于或等于”来验证命中计数。
假设有一种情况,我们需要在三次迭代后暂停执行并检查产品列表值。因此,我们选择“命中计数”选项作为条件,并在第二个下拉列表中选择“等于”选项,并在其旁边的文本框中键入 3。这意味着当循环第三次运行时,执行将在第 27 行暂停,从而命中断点。运行应用程序并等待断点命中。
请注意,条件信息是实时的。它显示当前的命中计数。当命中计数为 3 时,应用程序在调试点停止。此时,计数也可以更改,让我们将其更改为 4,或者可以简单地重置,并且仍然可以使用数据工具提示来查看变量。如果我们将鼠标悬停在产品列表上,我们可以看到它已经包含两个产品 (prod),因此我们必须在循环的第三次迭代中,因为我们在添加到列表之前中断。
Visual Studio 2015 断点配置的一个有趣功能是,如果断点被意外删除,可以使用 Ctrl+Z 再次应用它。
如果我们想在特定的命中计数或某个特定的命中间隔处命中断点,则可以随时使用带有命中计数的断点条件。这通常在处理项目列表和递归方法时很有用。即使应用程序仍在运行,也可以选择添加另一个条件,让我们通过条件表达式添加它。我们将通过在此处添加条件表达式来检查这一点。假设我们希望当 prod 实例的产品代码为“0004”时命中断点。因此,当应用程序在断点处停止时,单击“添加条件”选项并添加条件表达式。
您可以添加多个条件并为所需的调试配置断点,以提高生产力。单击“添加条件”选项时,会添加一个新行,其中包含前面在应用“命中计数”断点时显示的所有可用选项。选择“条件表达式”选项,并在 prod.ProductCode=="0004"
为 true 时对其进行验证。请注意,您可以在表达式文本框中写入任何表达式。表达式可以是简单的,也可以是复杂的,带有多个 && 和 || 条件。此外,在键入时,IntelliSense 也会工作并帮助创建表达式。
如果您愿意,可以删除先前的命中计数条件,否则调试点将被多次命中。我在这里删除了先前的条件。运行应用程序,您将看到当断点处提到的条件变为真时,断点被命中。
我们在这里看到,一旦产品代码为“0004”的条件满足,执行就会立即停止。
Actions
让我们看看“操作”是如何工作的。默认情况下,当条件为真时,调试器将在特定断点处暂停。此行为也可以通过检查操作进行配置。可以选择记录消息,在提供的“消息”字段中输入所需的消息。
我们还可以输入我们选择的所需纯文本,并自定义消息以提高可读性和理解性。在这里可以使用美元符号 ($) 来显示系统值。当您在消息字段中键入美元符号时,您将获得可用于记录消息的所有伪变量的列表。
花括号 {} 用于显示来自应用程序或代码库的输出或变量,您还可以在消息字段中获得 IntelliSense 支持。您可以在输出窗口中记录消息。让我们尝试一下,尝试在此断点条件下记录一些内容。您还可以选择“继续执行”。此选项可防止调试器在每次命中断点时暂停。如果您想在不停止在断点处的情况下记录消息,可以选择此选项。
在“操作”消息字段中,我尝试在 prod 的产品代码 == "0004" 的条件为真时记录一条消息。我已经将消息字段配置为记录 $Function
、$TID
、$TNAME
以及 {prod}(即产品实例)和 prod.ProductCode
。请注意,我还使用了纯文本,如“Method :
”、“Product Instance”、“Product Code”来使我的消息更具可读性。我选择在不停止在断点处的情况下继续执行。让我们运行应用程序,看看会发生什么。
我们在“消息”字段中定义的所有信息都按预期记录在输出窗口中。所有详细信息以及我使用的纯文本都按照定义的相同顺序记录。您可以在每次命中断点时想要显示信息时随时使用“记录消息”操作。
全新改进的错误列表
Visual Studio 2015 中的新“错误列表”现在得到了很大的改进,您可以在其中获取编译器和代码分析错误和警告的实时列表。“错误列表”的主要改进包括显示错误代码,并链接到该问题的文档。您可以单击该链接在线查看文档。筛选功能已大大扩展。仍然可以按当前项目或文档进行筛选,但现在也可以按错误严重性、错误代码、一组项目或一组文件进行筛选。
Visual Studio 2015 中已删除最大错误限制。以前,当错误数量过多时,无法真正一次性知道有多少错误。每次我们修复一定数量的错误时,编译时都会显示更多错误。现在,您的所有错误和警告将一次性显示在“错误列表”中。让我们实际尝试查看错误列表的改进。我故意在 program.cs 类的 Main 方法中进行了一些更改以获取一些错误和警告。我从产品声明中删除了 var,添加了一个空的 catch 块和一个空的 finally 块。在编译代码之前,我还启用了“在生成时启用代码分析”选项。您可以通过右键单击您的项目,打开属性并在属性窗口中选择“代码分析”选项来找到此选项,通常它显示在最后,如图所示。
现在,当我们编译该代码时,我们按预期获得了一些错误和警告。
我们在这里看到我们从编译器以及代码分析器获得了错误和警告。CS 作为错误/警告代码的前缀表示它是通过编译器生成的,而 CC 在此处表示代码分析器。我们获得了所有预期的警告和错误。请注意,错误和警告具有各自的符号。顶部的选项卡显示 2 个错误、5 个警告和 1 条消息。您可以选择这些选项来筛选并查看您需要的内容。假设您不想看到警告和消息,那么您可以单击上面的相应选项卡以仅查看错误列表。请注意,每个错误代码都是链接的形式,当您单击任何错误代码时,它会将您重定向到其文档页面。让我们单击 CS 0103,即第一个错误“名称‘products’在当前上下文中不存在”。
我们看到该链接已重定向到 MSDN 链接,其中包含该错误的详细文档。
筛选功能已进一步扩展,可以按错误、警告和严重性进行筛选。要检查,只需单击错误列表的列顶部,其中显示错误/警告符号。
一旦您单击顶部,如上图所示,筛选选项将出现在那里,您可以单击该筛选图标以查看更多可用筛选的类型。
您可以通过选中或取消选中复选框来根据您的选择筛选列表。筛选选项广泛适用于代码和项目。您可以特别选择要包含的代码,如下图所示:
或者选择作为筛选器的项目或文件。
因此,您可以看到筛选选项已扩展以处理多个选项,从而提高了开发人员的控制、配置和生产力。
结论
在本文中,我们介绍了 Visual Studio 2015 中新的改进的调试技术。我们涵盖了具有几个实际场景的断点配置,并初步了解了新的改进的错误列表。这些选项也可以在 Visual Studio 的早期版本中找到,但 VS 2015 提供了改进且更易于发现的版本。在下一篇文章中,我们将介绍剩余的两个调试选项:PerfTips 和新的诊断工具窗口。