VS2017中自用部分插件的设置的翻译或功能介绍—— OzCode功能介绍(二)

OzCode
调试神器
官网/GitHub


说明
此篇为GitHub上的OzCodeDemo,可以从上面下载Demo查看,Demo中用例子详细讲解了OzCode的各个功能。
这里还有一篇对OzCode各功能的大致说明,来自于OzCode官网上的功能介绍
这里有一个好东西。
本篇文章编写时间为2019年4月14日,对应4.0.0.557版本。



该仓库包含几个开源演示,展示了OzCode的功能。 我们的目标是帮助用户探索OzCode,并了解它如何增强Visual Studio的调试。
每个文件夹都包含一个演示和一个易于理解的文本,该文档将解释有关该功能的更多信息,并显示常见用例。


Reveal(显示、加星标)

专注于真正重要的数据。

对象可以有许多属性,但在调试时,并非所有属性都对您有用。 您通常只对几个特定的属性感兴趣。 对于Customer类,它可能是ID和Username属性,对于3D空间中的Point类,它可能是X、Y和Z字段。 通过OzCode的“显示”功能,您最终可以专注于实际重要的数据。

点击Demo中如下图的“Reveal”按钮可以运行此演示示例。
在这里插入图片描述
请注意,已触发了断点。 似乎虽然我们的方法只能用于往海外(除美国外的海外)发送包裹,但不知何故,我们得到了一个应该使用本地运输方式运送的包裹:
在这里插入图片描述
因为没有人在Customer类上实现ToString而感到很烦恼,一开始HUD将使用默认的ToString实现,它只显示了类型名称,明显不是很有用。 此外,遍历DataTip中的Customer类可能很痛苦,因为它包含了很多字段。
将鼠标悬停在customer上以显示DataTip窗口。 然后使用’+'展开customer字段。
在这里插入图片描述
最后找到“FirstName”并点击旁边的“star”:
在这里插入图片描述
注意DataTip窗口和HUD如何相应更新:
在这里插入图片描述
类似的也可以使用星号添加“SurName”属性。
现在使用Call Stack Window返回方法的调用者,再次使用DataTip查看有多少Customer来自Paris(包括Jose Duke)。 由于它们都是Customer类的实例,因此我们之前用星号标记的FirstName会自动显示。
在这里插入图片描述
让我们为每个customer添加更多信息:从DataTip窗口展开其中一个custom,然后展开Address属性并为Country,State和City属性加注星标。 最后打开Address旁边的星号 - 以便将Address信息显示为Customer的一部分(使得更容易查看嵌套信息!)。
在这里插入图片描述
折叠当前customer并查看customer列表:现在我们可以看到所有选定的Customer及其地址。
找到错误和受影响的Customer应该变的很简单。
在这里插入图片描述


Search(查找、搜索)

在茫茫数据中找到它。

调试对象和集合时,通常会查找特定属性或字段,或者属性或字段中保存的值。 不幸的是,这通常涉及大量点击和滚动,或编写自定义调试特定代码。 即使在简单的结构中查找项目也不容易,更不用说在复杂的对象图中这样做了。 通过我们的“Search”功能,情况不再如此。 无论对象的大小或对象图的复杂程度如何,都可以快速轻松的搜索成员名称和值!

在此Demo中,我们将尝试找出与托管可扩展性框架(或MEF)有关的问题,该框架是.NET的一部分,使开发人员能够使用插件架构构建可扩展的应用程序,并且行为有点像依赖注入容器。 可能您已经注意到,我们的整个OzCode演示应用程序都建立在MEF之上!
点击Demo中如下图的“Search”按钮可以运行此演示示例。
在这里插入图片描述
立即弹出一个抛出异常的消息框:
在这里插入图片描述
No!这意味着发生了MEF故障,因为我们错误地在同一接口下注册了两个或更多不同的服务。 因此,当我们要求MEF为我们提供实现ITestComponent接口的接口时,MEF不知道要给我们哪个实现!
由于我们想在抛出异常时中断执行,我们有两个选项 —— 可以使用Visual Studio的内置异常设置对话框,或者只需按“Break on all CLR excetions”按钮:
在这里插入图片描述
再次运行Demo —— 这次调试器将在抛出异常的行上中断。
将鼠标悬停在container变量上,将弹出DataTip窗口。 单击DataTip底部的Search文本框,然后写下“Test”以搜索其中包含单词“Test”的对象/属性。 默认情况下,搜索将同时查看字段和属性的名称以及它们各自的值!
在这里插入图片描述
container内有两个名称非常相似的组件,但为了确认,我们需要深入挖掘。 再次搜索,这次寻找ITestComponent。
在这里插入图片描述
起初没有结果显示。 点击“Search deeper”按钮以显示在ITestComponent合约下注册的组件。 每次单击“Search Deeper”时,OzCode都会扩大搜索范围,并在对象图中更深入地查看两个级别。
在这里插入图片描述


Show All Instances(显示所有实例)

在内存中查找要探索的特定对象。

OzCode使得在内存中找到您想要探索的特定对象变得微不足道。 只需打开“Show All Instances of Type(显示所有的类型实例)”,您就可以看到当前在内存中的该类型的每个对象。 为什么那个对象仍在内存中? 是否有任何包含此值的对象? OzCode令人兴奋的新探索工具毫不费力的立即回答了这些问题以及更多问题。

点击Demo中如下图的“Show All Instances”按钮可以运行此演示示例。
在这里插入图片描述
立即弹出一个抛出异常的消息框:
在这里插入图片描述
信息量不大,我们需要进一步研究这个问题。
为了理解问题,我们需要在抛出异常时中断,可以使用Visual Studio的内置异常设置对话框,或者只需按“Break on all CLR excetions”按钮:
在这里插入图片描述
重新运行Demo —— 您应该在调用SendInvoice时中断:
在这里插入图片描述
快速检查后应该显示此方法调用的问题 —— customerEmail为null,这不应该发生。
在这里插入图片描述
不幸的是InvoiceService的实现使我们很难找到导致问题的Customer。 虽然我们可以通过添加check来快速解决这个问题,但我们仍然需要找到有问题的customer!由于我们只有invoiceID,我们可以使用OzCode的Search来查找它。
使用watch查看pendingInvoiceId并选择“Copy Value”:
在这里插入图片描述
然后,将您的光标放在上面的“Customer”(类名)上,打开QuickActions菜单:
在这里插入图片描述
选择“显示所有Customer实例”以显示对话框。 将invoice值粘贴到seatch框(底部)中以搜索刚复制的invoiceID:
在这里插入图片描述
使用小“眼睛”我们可以展开所选customer以查看所有实例属性,查找emailAddress:
在这里插入图片描述
最后,我们可以看到该customer是在没有emailAdress的情况下加载的,这意味着我们手上可能存在数据损坏问题。
在这里插入图片描述


Setting Conditional Breakpoints(设置条件断点)

轻松直观的设置条件断点。

条件断点可以使调试更有效率,但没有OzCode,使用它们就像是一件苦差事。 OzCode使添加条件断点非常容易! 只需单击一下,OzCode就会根据特定的属性值设置条件断点,并为您预填充谓词。

点击Demo中如下图的“Conditional Breakpoins”按钮可以运行此演示示例。
在这里插入图片描述
一切似乎都没问题,没有抛出异常,运行成功完成! 直到我们收到(想象中的)电子邮件或电话,告诉我们至少有一位customer(“Robert Williams”)未获批准,并且未获得订单…
由于我们不知道为什么会发生这种情况,我们在PaymentValidation.Validate方法的开头添加一个断点。
为所有customer运行该方法几乎是不可能的。我们只想要在“Robert Williams”时停下。

  • 在“foreach”里将光标放在customer身上
  • 出现监视窗口时,展开customer属性并找到“FirstName”
  • 将光标放在第一个名称属性上,将出现“自定义动作”(魔杖)
  • 选择“Add conditional Breakpoint(添加条件断点)”

在这里插入图片描述
在新对话框中,将当前customer的first name替换为“Robert”:
在这里插入图片描述
为了确保我们不会意外地中断错误的customer,我们也想添加customer的surname('Williams”)。
有两种方法可以实现这一目标:

  • 添加“&&”,复制现有文本,并将“‘Robert”替换为’Williams’’,“FirstName”替换为“SurName”(或任何其他属性 —— OzCode支持代码完成)
  • 在保持条件断点编辑器窗口打开的同时,将鼠标悬停在“customer”上以显示DataTip窗口,将鼠标悬停在“SurName”属性上,然后按下“+”符号

在这里插入图片描述
然后准备运行。
在这里插入图片描述
点击“OK”关闭条件断点对话框,然后点击F5继续运行,直到我们到达“Robert Williams”。
现在,如果我们点击代码执行(F11),我们就会遇到有问题的方法。 似乎有人忘记添加对Robert Williams信用卡的支持(或者在没有支持的情况下添加了新卡)。
在这里插入图片描述
现在我们可以使用条件断点来检查是否还有其他不受支持的信用卡:

  • 将您的光标放在“CCType”上并选择“Add conditional Breakpoint”
  • 更新条件,以便在执行任何其他非“Visa”或“MasterCard”的信用卡时中断

在这里插入图片描述
再次运行该程序并检查。


Exception Trail(异常跟踪)

通过即时导航到最内部的InnerException,并深入了解异常的callstack和相关数据,毫不费力地理解错误的根本原因。

如果没有OzCode,调查异常是一项沉闷的任务 —— 浏览内部异常的踪迹,滚动浏览冗长的callstack,并睁大眼睛观察异常的相关数据以尝试理解错误。 使用OzCode,可以方便的在工具窗口中显示有关异常的所有相关信息。 您可以使用超级方便的breadcrumb控制栏来浏览每个内部异常,甚至可以直接在Visual Studio中启动Google或stackoverflow搜索!

点击Demo中如下图的“Exception Trail”按钮可以运行此演示示例。
注意:对于此演示,请确保break on exceptions是关闭的。
在这里插入图片描述
可能需要几次尝试,但过了一段时间后,您应该在捕获异常后中断:
在这里插入图片描述
通过从栏中选择查看View exception details(查看异常详细信息)或从quick actions(快速操作)菜单(侧面)选择打开Exception Trail(异常跟踪)。
在这里插入图片描述
我们可以看到异常详细信息的摘要 —— 有三个内部异常,抛出的第一个异常是IllegalOrderException。从这里我们可以轻松地浏览内部异常,以及通过其中一个受支持的提供方(比如谷歌)搜索有关异常类型或消息的其他信息(点击左侧的小放大镜按钮):
在这里插入图片描述
另一个节省时间的功能是能够转到抛出异常的位置 —— 快速找到问题的根本原因。 您可以从Excpetion details dialog(异常详细信息对话框)或异常栏中执行此操作。
在这里插入图片描述
您将直达异常来源而无需遍历异常及其内部异常。


When Set… Break

您是否在调试时挠头,问自己“这个属性的值来自哪里?”。 下一次,只需创建一个Setter Point!当属性值改变时,OzCode将进入调试器,允许您检查程序的状态,并确切地说明为什么有疑问的值首先到达了那里!

最难解决的问题是那些涉及变化状态的错误。 如果在程序执行期间的某个时刻某些对象的状态变得无效,您怎么办?但是您不确切知道它到底是什么时候以及在哪里变化的? 在检查调试器中的值时,当您发现有问题的属性值时,请使用魔术棒并选择“When Set – Break”。 下一次更改属性值时,OzCode将进入调试器并允许您检查程序的状态,并首先确定该问题值的确切位置! 这些Setter Breakpoints(属性断点)适用于常规属性和自动属性,甚至可以在没有源代码的属性上添加Setter Breakpoint!

点击Demo中如下图的“When Set… Break”按钮可以运行此演示示例。
在这里插入图片描述
运行完成后,将显示一条日志消息。 通过日志消息,您可以发现一个问题:似乎某些customers被错误地收取了其他人的订单(发送的invoices)。
在这里插入图片描述
快速浏览代码将显示我们将要发送账单的Customer从OrderInfo.Customer中取出,OrderInfo.Customer在ProcessOrder开头的对象构造期间初始化:
在这里插入图片描述
很明显,有人(某种程度上)改变了Customer财产。 那个人应该被解雇!但是现在我们有两个选择 —— 我们要么逐行运行程序,直到我们找到代码的违规行,或者使用OzCode的When Set功能。

  • 要使用该功能,我们首先需要在创建orderInfo后停止。再次运行Demo,直到到达断点,并将鼠标悬停在新创建的OrderInfo实例上
  • 现在展开OrderInfo对象的属性,并将鼠标悬停在Customer上
  • 将指针移到出现的魔术棒上
  • 从When Set菜单中选择Break

在这里插入图片描述
下图的提示框将出现:
在这里插入图片描述
由于我们想要在任何OrderInfo实例上中断,请保持选中第一个单选按钮。
问题是我们不想打破初始对象创建(因为其也设置Customer属性),因此为了优化断点,添加以下条件:

this.Customer != null

设置条件时,可以使用两个特殊关键字:

  • value:即将设置的新值
  • this:包含即将设置的属性的对象

注意:由于有完整的IntelliSense支持,因此在条件中使用value和this是很简单的事情!
因此,通过删除刚刚初始化值的情况,可以消除误报:
在这里插入图片描述
点击“OK”来设置新的断点,之后点击“F5”。
不要忘记删除“常规”断点,以便不会在每次执行迭代时停止。
触发新断点后,我们可以使用Reveal查看新数据:只需将鼠标指针移到新值上,然后“标记”您想要查看的信息即可。
在这里插入图片描述
使用StackTrace返回调用方法(OrderProcessing.ShipOrder),找出错误的根本原因:
在这里插入图片描述


Filter Collections(过滤集合)

使用我们的Filter Collections(过滤集合)功能,您可以将过滤表达式应用于任何集合

在代码中对集合过滤相对容易,并且有很多方法可以做到这一点。 但是如何在调试时进行过滤呢? 例如,您有一组Customer对象,并且您希望过滤超过35岁的对象。 Visual Studio的即时窗口和监视窗口不支持lambdas。 使用我们的过滤集合功能,您可以将过滤表达式应用于任何集合。 要解决customer问题,请选择customers 集合并将其过滤设置为:DateTime.Today.Year - [obj].Birthday.Year > 35,按Enter键并立即查看结果。 过滤集合后,过滤的结果也可以使用其他的所有功能。

点击Demo中如下图的“Filter Collections”按钮可以运行此演示示例。
在这里插入图片描述
(如果你运行在Break on Exceptions上,在这种情况下你可以跳过下一步)

立即弹出一个抛出异常的消息框。
关闭消息框并使用“Break on all CLR excetions”按钮,以便在抛出异常后中断。
在这里插入图片描述
再次运行此Demo。这次你应该以下方法上中断。 现在很容易理解抛出异常的原因 —— 我们只有一个符合条件的customer:
在这里插入图片描述
查看代码,我们看到31个customers进入LINQ语句,但只有一个出来。
逐个浏览customer集合可能需要一段时间 —— 使用过滤它来显示遵循特定规则之后的对象。

  • 将鼠标悬停在customers集合上
  • 点击魔杖
  • 选择Edit Filter(编辑过滤器)

在这里插入图片描述
现在我们可以使用[obj]作为过滤对象来更新集合过滤器,并且支持intellisense。
在这种情况下,我们可以使用以下过滤器来尝试查看问题是否为我们没有足够的62岁以下的customers:

[obj].Age < 62

打开Watch对话框(将鼠标悬停在customers上)将显示一个小漏斗。
将指针移到漏斗上将显示只有5个customers在62岁以下。
在这里插入图片描述
显然我们有一个问题。 现在让我们替换过滤条件,以显示超过62岁的所有customers。
在这里插入图片描述
我们得到有很多customers。 使用Reveal通过为其中一个customer标记Age属性来显示customer年龄:
在这里插入图片描述
现在我们需要做的就是找到Age属性的计算方法并修复bug。


Trace(追踪)

当事情变得麻烦时,您可以在程序执行期间在关键点轻松添加动态日志记录,然后使用OzCode投射到Visual Studio中的全功能集成日志查看器查看输出。

当您调试一个棘手的问题时,特别是在调试遗留代码或大量多线程场景时,单步执行代码来弄清楚系统正在做什么感觉就像试图同时处理12个球一样。 使用OzCode,当事情变得棘手时,您可以在程序执行期间在关键点轻松添加动态日志记录,然后使用OzCode投射到Visual Studio中的全功能集成日志查看器中查看输出。 您不再需要停止调试,添加日志记录代码,然后在每次添加简单跟踪时重建! 只需对要跟踪的值使用“Create Tracepoint(创建跟踪点)”命令即可。 Tracepoint就像一个断点,只是它不会破坏程序的执行,它会写一条跟踪消息。

点击Demo中如下图的“Trace”按钮可以运行此演示示例。
在这里插入图片描述
片刻之后,将出现Assertion Failed对话框:
在这里插入图片描述
点击Retry(重试)将使Visual Studio跳转到违规代码。 现在我们可以看到并非所有事件都成功记录(在这种情况下,100个中只有43个)。
注意:如果您在打开“Break on Exceptions异常中断”的情况下运行,则会在对话框出现之前停在同一行。
在这里插入图片描述
转到EventProcessor类中的HandleNextEvent方法。 现在在使用LogBook的Write方法的行中添加一个断点并再次运行。
在这里插入图片描述
一旦程序在断点处停止,我们就可以创建第一个跟踪点。
为此,只需将鼠标悬停在想要在跟踪上显示的对象(在本例中为loggingEvent),然后等待监视窗口出现。
在监视窗口中,转到Id属性并单击魔棒。
从打开的自定义操作对话框中,选择“ Create Tracepoint with value(使用值创建跟踪点)”。
在这里插入图片描述
将出现一个新对话框,其中包含您已选择的值(Id)。 从这里,您可以自定义跟踪消息并使用实例名称添加更多值(具有完整的智能感知支持),或者使用监视窗口。
在Tracepoint对话框中使用监视窗口时,现在会出现一个新图标。 点击该图标会将该值添加到当前Tracepoint。
在这里插入图片描述
添加完所有感兴趣的值并自定义完美日志消息后,单击“OK”关闭对话框。
运行到下一行,然后在那里放置一个断点或将光标移动到下一行并选择Run to cursor(Ctrl + F10)。
在该行中,使用事件的Id和结果值创建另一个跟踪点。

在这里插入图片描述
完成后,点击“OK”并继续运行该程序。
请注意,Visual Studio右下角会出现一个新图标,其中包含已记录的跟踪点数。
在这里插入图片描述
点击计数器将打开我们添加的跟踪点窗口,它可以帮助我们了解出了什么问题。
我们可以看到每个跟踪消息以及线程和进程,以及完整的堆栈跟踪。 所有列都可以按值进行过滤,并且有一个搜索框可以搜索包含特定文本的消息。如果这还不够,您可以随时将跟踪导出到Excel继续调查…
在这里插入图片描述
调查跟踪消息表明程序正在尝试同时写入许多消息。 在下面的示例中,在写入消息9时,来自其他线程线程的几条消息未成功。 写入9时触发跟踪的所有消息都没有写入(例如:8,11,10)。在整个应用程序运行中还可以观察到类似的许多行为。
在这里插入图片描述
由于我们没有打算从不同的线程中记录消息,因此我们需要弄清楚为什么会发生这种情况,通过查看类的开头,我们可以找到导致矛盾行为的Timer。


Magic Glance(魔术一览)

显示您已逐步完成的每一行的总结摘要。

Magic Glance可通过单击工具栏的眼镜图标(或按“Shift+Alt+Q”快捷键)切换,通过向您显示所执行的每行代码的摘要,为您提供对代码更深入的了解。

点击Demo中如下图的“Magic Glance”按钮可以运行此演示示例。
在这里插入图片描述
一旦在方法开头停止后,在方法结尾处添加另一个断点,然后按F5继续执行。 在断点处停止后按F10(跳过) —— 您应该在屏幕上看到以下内容:
在这里插入图片描述
这里可以看到两件事情:

  • 返回的值显示在方法的最后一行上方。
  • 该线左侧有一个蓝色眼镜图标。

点击 purple glasses(紫色眼镜)将显示最后一行的细致分解值:
在这里插入图片描述
现在将光标拖动到方法的开头或点击F5查看下一次迭代。
这一次使用F10逐行调试每一行。
注意到你调试的每行附近会出现的一副眼镜吗? 这是OzCode保存调试值以备不时之需。
在这里插入图片描述
当您调试每一行时,当前值将显示在变量上方。 布尔子句以绿色或红色标记(true / false),并根据执行标记条件路径。
到达最后一行。 您可以采取一些措施来分析上次的执行:
使用鼠标按下其中一个眼镜图标,或使用Alt和数字(例如Alt + 3)打开该行的Magic glance(魔术一览)。
在这里插入图片描述
进入Magic Glance模式后,您可以使用ALT + 向上/向下箭头在行间移动,或按下Escape来关闭Magic Glance。
另一种选择是使用Magic Glance工具栏按钮自动切换显示所有的HUD信息。
在这里插入图片描述
尝试在启用工具栏的情况下运行另一次迭代,看看您喜欢的工作方式是哪种。


Predict the Future(预测未来)

OzCode对代码的执行进行预测分析(或者我们喜欢称之为:算命!)。

OzCode预测未来!当我们点击F10时,你会看到一个箭头指向我们要去的地方,并且不相关的代码路径是半透明的。Predict通过为您提供调试时所做更改的即时反馈,为术语“Living Coding(实时编码)”带来了新的含义,使您能够非常快速地修复愚蠢的小编码错误。

点击Demo中如下图的“Predict”按钮可以运行此演示示例。
在这里插入图片描述
你应该会在方法的开头中断。
在switch语句的行上放置一个断点并继续调试运行(F5)。
在这里插入图片描述
一旦到达断点,你可能会注意到一些事情:将采取的case是唯一没有变灰的情况(Gender.Female),并且有一个箭头指向该case的开头。
在这里插入图片描述
继续运行 —— 下次调试器在断点处停止时,灰色部分将更改为显示下一个执行的指令 —— 在这种情况下为Gender.Male。
在这里插入图片描述
点击F10移动到下一条指令,if子句应该亮起。 红色表示失败的条件,而通过(true)的条件以绿色标记。所有这些都将在代码运行之前就分析完毕。
在这里插入图片描述
由于四个条件的总结果为真,因此在 if 附近出现绿色对钩,并且在子句主体的开头附近出现黄色箭头。
现在在SendThankYouLetter(Customer customer)的开头添加一个断点。
在这里插入图片描述
运行程序直到在方法的开头停止 —— 你能发现这个错误了吗?
如果您使用的是VS2015,则可以使用“编辑并继续”并将“>”替换为“<=”。
在这里插入图片描述
点击F5继续调试。下次到达这个方法时,会出现另一个问题。 OzCode知道执行的下一条指令将导致NullReferenceException。 该异常的来源标记为红色(EmailAddress)。
在这里插入图片描述
现在我们知道了什么是bug,通过确保 if 子句可以处理null的电子邮件地址可以很容易的修复它。


Custom Expressions(自定义表达式)

使用我们的自定义表达式功能,您可以在任何对象类型上创建多个自定义表达式,这些表达式将像该类型的任何其他成员一样显示。 你甚至可以为你最感兴趣的自定义表达式加注星标。

调试时,有时您需要的信息不包含在对象的字段和属性中;相反,它是基于您的对象的计算或表达式。您可能会发现自己希望仅针对此特定调试会话拥有一组不同的属性。
例如,如果Customer类在其属性中有工资历史记录,但是为了修复错误,您真正需要看到的是customer的在某个特定年份的应缴费用,只需在Customer变量上选择“Add Custom Expression(添加自定义表达式)”即可,并写下您想要看到的表达式。表达式将显示为Customer类的属性,并包含表达式的值。

点击Demo中如下图的“Custom Expressions”按钮可以运行此演示示例。
在这里插入图片描述
你应该会在LINQ子句之前中断:
在这里插入图片描述
在我们解决此代码中的错误之前,让我们更容易找到customer的数据:
由于customer的名称由两个属性组合而成:FirstName和LastName —— 它需要一些工作来查找特定customer,而不是通过向customer类添加新的“属性”来更轻松地读取customer名称。
将鼠标悬停在customer集合上,直到出现观察窗口,然后将光标指向customer,点击魔术棒并从对话框中选择“Add custom expression(创建自定义表达式”)*。
在这里插入图片描述
使用[obj]完成对新的自定义表达式的添加,它表示实例*(在本例中是customer),因此新值将是[obj] .FirstName +“ ”+ [obj].Surname。
我们可以使用//来给新属性命名 —— 就像注释一样,写成[obj] .FirstName +“ ”+ [obj].Surname// FullName,我们为每个customer创建了一个新的“属性”实例。
在这里插入图片描述
现在我们有了一个新属性,我们可以使用Reveal,就像它是原始类的属性之一一样。
在这里插入图片描述
现在让我们按F10三次来继续执行。LINQ语句表示应该在他们生日到达前的剩余几天内退回给customers。
但是有一个问题:最后一个customer应该是第一个(“Ben”)但不幸的是要理解一下刚刚发生了什么事情。
在这里插入图片描述
由于DaysTillBirthday方法在此范围内有效,因此我们可以在自定义表达式中使用它。

  • 在监视窗口中单击Customer
  • 再次使用魔杖并选择“Create custom expression(创建自定义表达式)”
  • 在打开的对话框中写入:DaysTillBirthday([obj],today)// DaysTillBirthday
  • 按下新属性旁边的“星号”,这样我们就可以看到所有customers的值
    在这里插入图片描述
    请注意到“Ben Cribbs”的生日还有多少天:
    在这里插入图片描述
    什么可能导致这个问题? 也许他的出生日期与它有关(提示:闰年)。

Export(导出)

将对象的实例导出为C#,XML或json。

在此Demo中,我们将在调试期间使用Export来序列化实例并在相关的单元测试中使用它。

点击Demo中如下图的“Custom Expressions”按钮可以运行此演示示例。
在这里插入图片描述
从client端返回数据后,将中断在行中的断点上。 将鼠标放在featuredQuestions上,直到出现快速观察窗口。 然后选择魔术棒并从上下文菜单中选择“Export (导出)”。
在这里插入图片描述
将出现一个标题为“Export Results(导出结果)”的对话框。
在这里插入图片描述
注意我们如何只得到最顶层的项目(new Item()),使用“Choose Depth”来增加导出的类层次结构的深,确保它至少为5。
显示所有项目后,使用“Copy To Clipboard(复制到剪贴板)”,关闭对话框并停止调试。找到ExportUnitTests项目并打开QuestionAnalyzerTests.cs,然后将代码粘贴到LoadDataFromCode中替换掉new Rootobject()。
在这里插入图片描述
在该文件中运行单元测试(Ctrl + R,A),现在其中一项测试应该可以通过。

要修复第二个测试,您需要以json格式导出同一个类,并将结果复制到与测试位于同一项目中的questions.json中。


LINQ Debugging(LINQ 调试)

只有在VS2015和VS2017中支持。

使用LINQ时,开发人员不得不使用技巧来找出一次或多次迭代中特定步骤的值。 在某些情况下,甚至可能完全重写与命令式循环相同的代码,以便能够检查出错的地方。
OzCode添加了有助于理解查询功能的工具 —— 如果需要,可以一目了然方便的深入了解各种LINQ运算符之间传递的数据。

在这个Demo中,一个句子被分成单词并分组,以便我们可以返回最多出现的单词。
问题是返回了“code”,而不是“bugs”这个词。 使用OzCode,我们可以通过使用LINQ调试功能来调查此问题并修复错误。

点击Demo中如下图的“LINQ ”按钮可以运行此演示示例。
在这里插入图片描述
您将在方法的开头的一个断点处中断。 在这个Demo中我们有一个查询,它将一个句子中的单词分组并返回最常用的单词。 快速计数将告诉我们,在这种情况下该词是“bugs”(4次)。
在这里插入图片描述
运行到方法结束,你会发现一个问题:查询实际上返回“code”作为最常用的单词。
在这里插入图片描述
为了理解发生了什么,我们需要回到查询。将光标拖回第19行或再次运行演示直至到达该行。
你应该看到新的数字指示:
在这里插入图片描述
这些指示器显示每个操作员返回的条目数。 例如,Split将文本分成79个字符串,执行Where后只有29个字符串传递到下一步。
单击其中一个数字会打开LINQ DataTip,它将显示LINQ操作符生成的所有项目或操作符使用的所有项目。 单击某个项目将更新HUD,以便在浏览各种查询时显示这些项目。 您可以在下面看到原始文本中出现的两次“99”的情况。
在这里插入图片描述
点击Where子句的数字指示器将向我们显示筛选的单词列表,我们可以向下滚动以找到有问题的项目。可以通过拖动滚动条或更方便的使用鼠标滚轮。
你现在能看到这个bug吗? 如果还没有,不要担心,我们将深入研究代码。在快速工具提示栏或查询的左侧点击“lambda”图标。
在这里插入图片描述
点击其中一个lambda将打开详细的查询工具窗口,您可以在其中逐步的调查此次查询。
在这里插入图片描述
在此窗口中,您可以使用“Reveal”和“Search”来帮助调查问题。尝试搜索“bugs” —— 你现在可以看到问题了吗?
在这里插入图片描述
点击“BUGS)”并从上面的 "bread crumbs(就是上部的Source、Where、GroupBy等那一栏)"中点击“GroupBy”来查看问题。 这样你就可以在查询的各个阶段之间移动并查看到底发生了什么。
尝试跟踪查询中的一些条目并亲自查看。
在这里插入图片描述
现在您已经知道问题是什么了 —— 修复它并验证是否执行了想要让它最终执行的操作:
在这里插入图片描述


Compare Instances(比较实体)

如果您想要比较文件,可以使用diff应用程序来发现差异。 不幸的是,当您需要比较两个(或更多)物体时,您必须相信您的眼睛和记忆。 使用我们的比较功能,您现在可以花更少的时间观察,并通过简单的点击让OzCode比较对象和集合! 结果将以并排视图显示,可帮助您调查两个对象之间的差异和相似之处。

在这个Demo中,一个对象被序列化和反序列化,但是生成的对象有一些不同的值。 使用Compare,我们将找到这些差异,以了解发生了哪些变化并找到问题。

点击Demo中如下图的“Compare ”按钮可以运行此演示示例。
在这里插入图片描述
您将在方法的开头的一个断点处中断。
在这里插入图片描述
一直运行直到方法的最后一行Assert处,且没有直接通过它。 您应该看到Assert即将失败,因为loadedPhoneBook不等于原始phoneBook。
通过比较两个PhoneBook实例,可以轻松找到造成这种不相等的原因。 首先将鼠标悬停在phoneBook上,直到Quickwatch(快速查看)窗口出现,然后点击compare的图标。
在这里插入图片描述
比较窗口将出现。 注意所有可比较的对象(例如loadedPhoneBook)
在这里插入图片描述
现在选择loadedPhoneBook进行比较。 使用combobox下拉框或将鼠标悬停在loadedPhoneBook上并按下比较按钮(类似于如何选择phoneBook实例)。
点击Compare按钮将出现以下窗口:
在这里插入图片描述
点击“Show differences only(仅显示差异)”,然后点击“Search deeper(更深入搜索)”。红色标记两个实例之间的不同:
在这里插入图片描述
现在您可以使用“+”符号浏览改变了哪些属性,也使用眼睛图标查看整个对象,来找出序列化/反序列化期间被确实更改的内容。
在这里插入图片描述


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值