来源: C# 线程手册 第六章 线程调试与跟踪 代码跟踪 – DanielWise – 博客园
我们下一个将要分析的代码检测技术是跟踪。在一个多线程应用程序中,这个技术非常重要。当已经启动了多个任务时,你可以跟踪一个线程的行为和相互之间的各个线程之间的影响。我们稍后将看到在这种情况下使用调试器是不现实的。.NET Framework 提供了很多有用的类来帮助开发人员轻松地实现跟踪功能。让我们看一下.NET Framework 提供的System.Diagnostics 命名空间中的跟踪类。
1. Trace: 这个类有很多向一个监听器写消息的静态方法。默认情况下,VS.NET 中的调试输出窗口将被用来作为监听程序,由于使用了监听器集合,所以你可以添加不同的监听器,比如文本监听器或者Windows事件日志监听器。
2. Debug: 这个类的方法和Trace 类的一样,都向一个监听器应用程序中写入信息。这两个类在使用上最大的不同是,Trace 用于运行阶段,Debug 用于开发阶段。
3. BooleanSwitch: 这个类允许我们定义一个开关来打开/关闭跟踪消息。
4. TraceSwitch: 这个类提供四个不同的跟踪级别来帮助开发人员选择发送不同级别的消息给监听器。
Trace 类
在这部分,我们将分析Trace 类中使用最频繁的几个方法。这些方法由.NET Framework包装好后提供给我们。Trace 类位于System.Diagnostics 命名空间中并提供很多静态方法来发送消息给监听程序。
下表列出来由Trace 类提供的一些静态方法:
这些方法的默认行为取决于选择的监听器程序。例如,当使用默认监听器的时候,Assert() 方法会显示一个消息框。
默认监听器程序
Trace 类提供一个允许我们添加一个新的监听器程序的监听器集合。当没有向监听器集合中添加新的监听器对象时,Trace 类就会使用默认的监听器程序:调试输出窗体。这个窗体由Visual Studio.NET IDE 在调试过程中提供。让我们来看一个简单的例子,TraceExample:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:Daniel Dong * Blog: www.cnblogs.com/danielWise * Email: guofoo@163.com * */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace TraceExample { class Program { static void Main(string[] args) { Trace.WriteLine("Enter Main()"); for (int i = 0; i < 6; i++) { Trace.WriteLine(i); } Trace.WriteLine("Exiting from Main()"); } } }
这段代码真的非常简单;当进入和退出Main() 方法时它打出调试信息,在循环中累加变量值。在下一个截图中,你可以看到Visual Studio.NET 输出监听器是如何显示信息的:
Trace 类也提供了两个有用的方法来断言错误提示:Assert() 和 Fail(). 前者允许开发人员检查作为参数传入的条件是否满足并在条件不满足时向监听器中写入一条消息。后者会在每次发生失败时向监听器中写入一条消息。当监听器集合中没有其他监听器对象时,Assert() 方法显示一个消息对话框来提供用户断言失败。下面的代码片段,TraceAssert.cs, 可以在SQL Server 服务被故意停止且引发一个连接错误的时候测试出来:
/************************************* /* Copyright (c) 2012 Daniel Dong * * Author:Daniel Dong * Blog: www.cnblogs.com/danielWise * Email: guofoo@163.com * */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Threading; using System.Data.SqlClient; namespace TraceExample { class Program { [STAThread] static void Main(string[] args) { //Create a thread Thread t = new Thread(new ThreadStart(DBThread)); //Start the thread t.Start(); } private static void DBThread() { //Create a connection object SqlConnection dbConn = new SqlConnection(@"Data Source=DANIELFORWARD\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"); //Create a command object to execute a SQL statement SqlCommand dbComm = new SqlCommand("SELECT * FROM Region", dbConn); SqlDataReader dr = null; Trace.WriteLine(DateTime.Now + "- Execute SQL statement"); try { //Open the connection to the database dbConn.Open(); //Assert that the connection opened Trace.Assert(dbConn.State == System.Data.ConnectionState.Open, "Error", "Connection failed..."); //Execute the SQL statement dr = dbComm.ExecuteReader(System.Data.CommandBehavior.CloseConnection); //Assert that the statement executed OK Trace.Assert(dr != null, "Error", "The SqlDataReader is null."); while (dr.Read()) { //Reading records Trace.WriteLine(dr[0].ToString()); } } catch (Exception ex) { //Log the error to the Trace application Trace.Fail("An error occured in database access, details: " + ex.Message); } finally { if (!dr.IsClosed && dr != null) { dr.Close(); } } } } }
在Main() 方法中,创建并启动了一个新线程。新线程运行DBThread()中的代码。代码简单地连接了下SQL Server 的Northwind数据库,从Region表中收集所有数据。如果SQL Server 不可用,在执行代码过程中会弹出下面的断言失败窗体。
引发异常断言的代码为:
Trace.Assert(dbConn.State == System.Data.ConnectionState.Open, "Error", "Connection failed...");
你可以看到,第一个参数检查连接状态是否打开。当连接没有打开时它将被设置为false, 然后会显示断言失败。你将会从本章的后续部分了解到也可以使用配置文件禁用消息跟踪。那样的话,你就可以在运行时决定是否显示断言消息。