这一课讲解自定义视图调试和多线程调试的一些方法
我们在调试过程中可以看到很多的数据,难以定位到我们所需要的数据,并且也不知道我们看到的数据是属于属性还是字段是静态的还是非静态的。有些内部信息在调试的时候我们也不希望别人可以看到。我们还需要自定义默认数据视图。
首先介绍的是如何在debug时隐藏一个字段或属性的显示,我们通过
- [DebuggerBrowsable(DebuggerBrowsableState.Never)]
这个Attribute来规定字段或属性的显示,DebuggerBrowsableState.Never表示永不显示,还有Collapsed表示折叠起来,RootHidden根隐藏
还有几个来描述debug信息的Attribute
DebuggerDisplay – 改变数据变量的显示值,当添加了此Attribute,在debug时观察对象的时候会显示你定义的值
DebuggerTypeProxy– 不同类型视图
DebuggerVisualizer – 自定义视图
这些Attribute都在System.Diagnostics命名空间下
当我们跟踪到自定义一个类的时候,我们发现这个类定义的对象的默认值是这个类的类名
我们如何修改这个默认的value,实际上我们只要重写ToString方法就可以了
实际上Department类的ToString方法已经覆盖了基类的ToString的方法,基类的ToString方法是返回类名信息。
通过DebuggerBrowsable的Attribte来隐藏字段或属性是没有问题的,但是当我们类里的字段或属性非常多的时候,难道我们要每个字段或属性都来添加这个Attribute,那样太繁琐了,我们可以通过代理的方式来解决这个问题
如我们有一个Employee类
- 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;
- public Employee(int id, string firstName, string lastName, string email, DateTime hireData, Address address, Department department, Image photo)
- {
- _id = id;
- _firstName = firstName;
- _lastName = lastName;
- _email = email;
- _hireData = hireData;
- _address = address;
- _department = department;
- _photo = photo;
- }
- public Department Department
- {
- get
- {
- return _department;
- }
- set
- {
- _department = value;
- }
- }
- public string FirstName
- {
- get
- {
- return _firstName;
- }
- set
- {
- _firstName = value;
- }
- }
- public int ID
- {
- get
- {
- return _id;
- }
- set
- {
- }
- }
- public string LastName
- {
- get
- {
- return _lastName;
- }
- set
- {
- _lastName = value;
- }
- }
- }
我们可以为这个Employee类,添加一个代理类EmployeeProxy类
- 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;
- }
- }
在EmployeeProxy类中,我们定义了ID,Name,DepartementName,用来表示我们在调试信息是需要显示的字段,在构造函数中,我们使用Employee类作为构造函数,并且将需要的信息赋值给EmployeeProxy类理的字段然后我们需要在Employee类上添加一个Attribute
- [DebuggerDisplay("{_firstName} {_lastName}")]
- [DebuggerTypeProxy(typeof(EmployeeProxy))]
- class Employee
DebuggerTypeProxy就是来管理Employee类对应的代理类的。那么我们调试时将会显示
原始视图将显示真正的Employee类中的字段和属性,那么DebuggerDisplay就是表明我们不使用ToString的方法来改变查看类的显示的值,也就是说替换了ToString的在Debug时的功能。
我们知道在调试时,二进制流的图片是没有可视化的功能的,我们如果需要自定义这种功能。
我们可以先自定义一个form窗口用来显示图片
- public partial class ImageForm : Form
- {
- public ImageForm(Image image)
- {
- InitializeComponent();
- this.pictureBox1.Image = image;
- }
- private void ImageForm_Load(object sender, EventArgs e)
- {
- }
- private void ImageForm_Shown(object sender, EventArgs e)
- {
- }
- }
当Image对象作为参数传递给form的构造函数的时候,我们将image的值赋值给picturebox,用picturebox来显示图形。
- //可视化工具类,继承于DialogDebuggerVisualizer类也就是对话框调试可视化类
- public class DebuggerSide : Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer
- {
- //重写Show函数
- protected override void Show(Microsoft.VisualStudio.DebuggerVisualizers.IDialogVisualizerService windowService, Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider objectProvider)
- {
- //判断windowService是否为空
- if (windowService != null)
- {
- //从对象提供者从获取到要可视化的对象
- Image image = (Image)objectProvider.GetObject();
- //实例化显示图片的窗体
- ImageForm imageForm = new ImageForm(image);
- imageForm.ShowDialog();
- }
- }
- }
在生成了ImageForm和DebuggerSide类库后(注意工程文件是类库的类型),需要将生成的dll拷贝到我的文档下的Visual Studio 2005/Visualizers目录下,那么我们就可以通过这种方式来自定义数据类型的调试视图。
多线程程序调试
多线程程序调试是比较困难的,我们为什么需要进行多线程调试呢?因为我们在winform程序中,许多获得数据,处理数据都需要使用异步的方式来进行,这样才能提高用户体验
在我们调试多线程程序时,当程序运行起来并命中断点时,我们可以用调试菜单-窗口-线程菜单来打开线程窗口
我们可以通过这种方式来查看线程的信息。
我们还可以在选中的断点的地方点击右键选择条件
在条件窗口我们可以写一些条件,比如我们在循环中我们就可以设置条件为i==5,那么当i==5的时候,就会命中断点,等于其他值的时候不会命中断点。
断点过滤
• 可以使用以下方法过滤断点
–线程ID或者名称
–进程ID或者名称
–机器名称
• 对于分布式应用程序有着很大必要
也就是说我们可以利用断点过滤来专门调试某个线程、进程或机器来命中的条件
命中次数:命中次数表明当断点命中多少次之后才会真正的停止下来让开发人员观察数据
命中断点时:命中断点时是用来当断点命中时,执行定义的命令
XSL转换调试
• 在Microsoft® Visual Studio® 中调试XSL:
–单独XSLT文档
• XML->Debug XSL
– XSLT文档通过应用程序加载
• 执行XSLTProcessor.Execute()
• 可以使用基本调试功能
–单步执行,本地数据,断点等等
设计时表达式计算:这个就是在立即窗口中执行代码也可以在鼠标监视中直接修改变量的值