托管代码的增强调试
缺省情况下的调试窗口,存在以下问题
1. 过多的不需要关心的信息
2. 重复信息
3. 不完善的层次化视图
• 数据窗口通过树型视图来显示
• 不是所有的类型都能通过层次来显示
–信息在数据内部
–信息之间的关系
为了解决上面的问题,我们可以自定义数据视图
自定义数据视图
• System.Diagnostics属性:
– DebuggerBrowseable – 隐藏成员
– DebuggerDisplay – 改变数据变量的显示值
– DebuggerTypeProxy – 不同类型视图
– DebuggerVisualizer – 自定义视图
• ToString 描述对象信息
• 许多框架类型都已经被属性化
在上面的重复信息中,我们可以通过实现ToString方法来调用所希望的信息
注意要引用命名空间Using System. Diagnostics
我们首先看看Address类的定义
using System;
using System.Collections.Generic;
using System.Text;
namespace DebugDemo
{
class Address
{
private string _addressLine1;
private string _addressLine2;
private string _city;
private string _phone;
private string _postalCode;
public Address(string addressLine1, string addressLine2, string city, string phone, string postalCode)
{
_addressLine1 = addressLine1;
_addressLine2 = addressLine2;
_city = city;
_phone = phone;
_postalCode = postalCode;
}
public void New()
{
throw new System.NotImplementedException();
}
}
}
假设程序的入口文件如下
using System.Data;
using System.Diagnostics;
namespace DebugDemo
{
class Program
{
static void Main (string[] args)
{
double real = System.Math.Sqrt(934);
real = Double.Parse("3.34");
Address address = new Address(" changchun road", null, " jilin ", "0432", "132000");
Department department = new Department(34, "nedu");
Debug.Print(department.ToString());
Employee employee = new Employee(1205, "lh", "l", "llh@hotmail.com", DateTime.Now, address, department, Image.FromFile(@"jl.jpg"));
}
}
}
这时候我们在调试的时候,查看address的信息,会看到一些莫明其妙的信息
如果我们实现类的ToString方法,你会看见什么?
Public override string ToString()
{
return _addressLine1 + "," + _addressLine2 + "," + _city + "," + _postalCode;
}
下面我进一步看看Department的定义
class Department
{
private int _id;
private string _name;
public Department(int id, string name)
{
_id = id;
_name = name;
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public void New()
{
throw new System.NotImplementedException();
}
public string ToString()
{
return "id:" + _id + ",Name:" + _name;
}
}
调试过程的截图:
这样我们在调试的时候如果要隐藏一部分信息,如何做到?
很简单,按照下面就禁止Name属性了
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public string Name
我们再看看Employee类的定义
[DebuggerDisplay("{_firstName} {_lastName}")]
[DebuggerTypeProxy(typeof(EmployeeProxy))]
class Employee
{
private Address _address;
private Department _department;
private string _email;
private string _firstName;
private DateTime _hireData;
private string _field;
private int _id;
private string _lastName;
private Image _photo;
}
普通情况下,看看调试过程中是怎么显示的:
我们能够看都信息纷繁复杂,现在我们对代码进行修改,我们会看到不一样的东西:
[DebuggerDisplay("{_firstName} {_lastName}")]
[DebuggerTypeProxy(typeof(EmployeeProxy))]
class Employee
至于EmployeeProxy的定义如下
using DebugDemo;
using System.Diagnostics;
class EmployeeProxy
{
public int ID;
public string Name;
public string DepartmentName;
public EmployeeProxy(Employee employee)
{
ID = employee.ID;
Name = employee.FirstName + " " + employee.LastName;
DepartmentName = employee.Department.Name;
}
}
这样调试后的效果如下:
最后我们看看如何在Watch窗口查看图片?
首先我们在工程中增加一个类库,添加一个窗体,并在上面放入一个图片控件
public partial class ImageForm : Form
{
public ImageForm(Image image)
{
InitializeComponent();
this.pictureBox1.Image = image;
}
}
再添加如下的类:
using System.Diagnostics;
[assembly: DebuggerVisualizer(typeof(ImageVisualizer.DebuggerSide), Target = typeof(Image), Description = "Image Visualizer")]
namespace ImageVisualizer
{
public class DebuggerSide : Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer
{
protected override void Show(Microsoft.VisualStudio.DebuggerVisualizers.IDialogVisualizerService windowService, Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider objectProvider)
{
if (windowService != null)
{
Image image = (Image)objectProvider.GetObject();
ImageForm imageForm = new ImageForm(image);
imageForm.ShowDialog();
}
}
}
}
最后把这个工程编译后的dll文件放入如下目录中
My Documents/Visual Studio/Visualizers
<VS>/Common7/Packages/Debugger/Visualizers
最后点击
上面的放大镜,我们可以看到调试过程的图片
多线程程序调试
断点过滤
• 可以使用以下方法过滤断点
–线程ID或者名称
–进程ID或者名称
–机器名称
我们可以右击断点,你会看见调试过程的条件,通过设置这些条件属性,你会更加方便的调试程序
除此之外,我们还可以通过即时窗口,随时修改参数的值,如下