Click here to Skip to main content
15,891,657 members
Articles / Programming Languages / C#

A Treatise on Using Debug and Trace classes, including Exception Handling

Rate me:
Please Sign up or sign in to vote.
4.85/5 (31 votes)
12 Oct 200212 min read 272.9K   1.7K   193  
C#'s built in Debug and Trace classes can be confusing and inappropriately used. This article looks at one success story using debug traces and assertions, and presents an improved debug class.
using System;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;

namespace MyApp	// change this namespace as you wish
{
	// The problem/reason dictionary key type
	public class DbgKey
	{
		private string key;
		
		public string Name
		{
			get {return key;}
			set {key=value;}
		}
		
		public DbgKey(string s)
		{
			key=s;
		}
	}
	
	// The problem/reason object
	public class ProblemReason
	{
		string problem;
		string[] reasons;

		public ProblemReason(string s1, string[] s2)
		{
			problem=s1;
			reasons=s2;
		}
			
		public string GetProblem()
		{
			return problem;
		}
			
		public string[] GetReasons()
		{
			return reasons;
		}
	}

	// the problem/reason collection
	public class DbgProblemCollection
	{
		private SortedList probs;
		
		public DbgProblemCollection()
		{
			probs=new SortedList();
		}
		
		public void Add(DbgKey key, string problem, string[] reasonList)
		{
			probs.Add(key.Name, new ProblemReason(problem, reasonList));
		}
		
		public bool Contains(DbgKey key)
		{
			return probs.Contains(key.Name);
		}
		
		public int Count
		{
			get
			{
				return probs.Count;
			}
		}
		
		public ProblemReason this[DbgKey key]
		{
			get
			{
				return (ProblemReason)probs[key.Name];
			}
		}
	}
	
	public class Dbg
	{
		// The debug extensions:
		private static DbgProblemCollection problems=new DbgProblemCollection();
	
		// return the problem/reason collection
		public static DbgProblemCollection Problems
		{
			get {return problems;}
		}

		[Conditional("TRACE")]
		public static void InitializeUnhandledExceptionHandler()
		{
			AppDomain.CurrentDomain.UnhandledException+=new UnhandledExceptionEventHandler(DbgExceptionHandler);
		}

		public static void DbgExceptionHandler(object sender, UnhandledExceptionEventArgs args)
		{
			Exception e=(Exception) args.ExceptionObject;
			Trace.WriteLine("Exception: "+e.Message);
			MessageBox.Show(
				"A fatal problem has occurred.\n"+e.Message,
				"Program Stopped",
				MessageBoxButtons.OK,
				MessageBoxIcon.Stop,
				MessageBoxDefaultButton.Button1);
			Trace.Close();
			Process.GetCurrentProcess().Kill();
		}
		
		// The Warn method is enabled in release mode
		[Conditional("TRACE")]
		public static void Warn(bool b, DbgKey key)
		{
			Trace.WriteLine("Warning: "+key.Name);
			if (problems.Contains(key))
			{
				string explanation=GetExplanation(key);
				MessageBox.Show(
					explanation,
					"Warning",
					MessageBoxButtons.OK,
					MessageBoxIcon.Warning,
					MessageBoxDefaultButton.Button1);
			}
			else
			{
				MessageBox.Show(
					"A problem has occurred that should be corrected.\n\nReference: "+key.Name,
					"Warning",
					MessageBoxButtons.OK,
					MessageBoxIcon.Warning,
					MessageBoxDefaultButton.Button1);
			}
		}

		// The Assert method is enabled in release mode
		[Conditional("TRACE")]
		public static void Assert(bool b, DbgKey key)
		{
			Trace.WriteLine("Assert: "+key.Name);
			if (problems.Contains(key))
			{
				string explanation=GetExplanation(key);
				MessageBox.Show(
					explanation,
					"Program Stopped",
					MessageBoxButtons.OK,
					MessageBoxIcon.Stop,
					MessageBoxDefaultButton.Button1);
			}
			else
			{
				MessageBox.Show(
					"A fatal problem has occurred.\n\nReference: "+key.Name,
					"Program Stopped",
					MessageBoxButtons.OK,
					MessageBoxIcon.Stop,
					MessageBoxDefaultButton.Button1);
			}
			Trace.Close();
			Process.GetCurrentProcess().Kill();
		}

		[Conditional("DEBUG")]
		public static void LogOutput(string fn)
		{
			Debug.Listeners.Add(new TextWriterTraceListener(fn));
			DateTime dt=DateTime.Now;
			Debug.WriteLine("Debug Logging Initialized: "+dt.ToString());
		}

		// Flag the debugger to break at the next instruction.
		[Conditional("DEBUG")]
		public static void Break()
		{
			Debugger.Break();
		}

		// Put together the list of possible reasons for the particular problem.
		private static string GetExplanation(DbgKey key)
		{
			ProblemReason ps=problems[key];
			string explanation=ps.GetProblem()+"\n\nPossible reasons:\n\n";
			int n=1;
			foreach (string sol in ps.GetReasons())
			{
				explanation+="  "+n.ToString()+". "+sol+"\n";
				++n;
			}
			return explanation;
		}

		/*
		 * Mirror the current Debug and Trace class functionality.
		 */
		
		public static bool AutoFlush
		{
			get {return Debug.AutoFlush;}
			set {Debug.AutoFlush=value;}
		}
		
		public static int IndentLevel
		{
			get {return Debug.IndentLevel;}
			set {Debug.IndentLevel=value;}
		}
		
		public static int IndentSize
		{
			get {return Debug.IndentSize;}
			set {Debug.IndentSize=value;}
		}
		
		public static TraceListenerCollection Listeners
		{
			get {return Trace.Listeners;}
		}
		
		[Conditional("TRACE")]
		public static void Assert(bool b)
		{
			Trace.Assert(b);
		}
		
		[Conditional("TRACE")]
		public static void Assert(bool b, string s)
		{
			Trace.Assert(b, s);
		}
		
		[Conditional("TRACE")]
		public static void Assert(bool b, string s1, string s2)
		{
			Trace.Assert(b, s1, s2);
		}

		[Conditional("TRACE")]
		public static void Fail(string s)
		{
			Trace.Fail(s);
		}
		
		[Conditional("TRACE")]
		public static void Fail(string s1, string s2)
		{
			Trace.Fail(s1, s2);
		}
		
		[Conditional("DEBUG")]		
		public static void Close()
		{
			Trace.Close();
		}
		
		[Conditional("DEBUG")]		
		public static void Flush()
		{
			Debug.Flush();
		}
		
		[Conditional("DEBUG")]		
		public static void Indent()
		{
			Debug.Indent();
		}
		
		[Conditional("DEBUG")]		
		public static void Unindent()
		{
			Debug.Unindent();
		}
		
		// Write
		
		[Conditional("DEBUG")]
		public static void Write(object obj)
		{
			Debug.Write(obj);
		}
		
		[Conditional("DEBUG")]		
		public static void Write(string s)
		{
			Debug.Write(s);
		}
		
		[Conditional("DEBUG")]		
		public static void Write(object obj, string s)
		{
			Debug.Write(obj, s);
		}
		
		[Conditional("DEBUG")]		
		public static void Write(string s1, string s2)
		{
			Debug.Write(s1, s2);
		}
		
		// WriteIf
		
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, object obj)
		{
			Debug.WriteIf(b, obj);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, string s)
		{
			Debug.WriteIf(b, s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, object obj, string s)
		{
			Debug.WriteIf(b, obj, s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteIf(bool b, string s1, string s2)
		{
			Debug.WriteIf(b, s1, s2);
		}
		
		// WriteLine
		
		[Conditional("DEBUG")]		
		public static void WriteLine(object obj)
		{
			Debug.WriteLine(obj);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLine(string s)
		{
			Debug.WriteLine(s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLine(object obj, string s)
		{
			Debug.WriteLine(obj, s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLine(string s1, string s2)
		{
			Debug.WriteLine(s1, s2);
		}
		
		// WriteLineIf
		
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, object obj)
		{
			Debug.WriteLineIf(b, obj);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, string s)
		{
			Debug.WriteLineIf(b, s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, object obj, string s)
		{
			Debug.WriteLineIf(b, obj, s);
		}
		
		[Conditional("DEBUG")]		
		public static void WriteLineIf(bool b, string s1, string s2)
		{
			Debug.WriteLineIf(b, s1, s2);
		}
		
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Interacx
United States United States
Blog: https://marcclifton.wordpress.com/
Home Page: http://www.marcclifton.com
Research: http://www.higherorderprogramming.com/
GitHub: https://github.com/cliftonm

All my life I have been passionate about architecture / software design, as this is the cornerstone to a maintainable and extensible application. As such, I have enjoyed exploring some crazy ideas and discovering that they are not so crazy after all. I also love writing about my ideas and seeing the community response. As a consultant, I've enjoyed working in a wide range of industries such as aerospace, boatyard management, remote sensing, emergency services / data management, and casino operations. I've done a variety of pro-bono work non-profit organizations related to nature conservancy, drug recovery and women's health.

Comments and Discussions