The BooleanSwitch
and
TraceSwitch
classes defined in the FCL may not
always have the required flexibility or fine-grained control that you
need. You want to create you own switch class that provides the level
of control and flexibility that you need. For example, creating a
class that allows you to set more precise trace levels than those
supported by the TraceSwitch
class.
The
TraceSwitch
class provides the following tracing
levels:
TraceError
|
TraceWarning
|
TraceInfo
|
TraceVerbose
|
However, you need a finer-grained set of levels, such as the following:
You can create your own switch class that inherits from
System.Diagnostics.Switch
and provides the level
of control that you need. For example, creating a class that allows
you to set more precise trace levels than those supported by the
TraceSwitch
class involves the following steps:
Define a set of enumerated values that represent the levels to be supported by your switch class:
public enum AppSpecificSwitchLevel { Disable = 0, Note = 1, Warning = 2, MinorError = 3, MediumError = 4, CriticalError = 5 }
Define a class, such as AppSpecificSwitch
, that
inherits from
System.Diagnostics.Switch
:
public class AppSpecificSwitch : Switch { protected AppSpecificSwitchLevel level = 0; public AppSpecificSwitch(string displayName, string description) : base(displayName, description) { this.Level = (AppSpecificSwitchLevel)base.SwitchSetting; } // Read/write Level property public AppSpecificSwitchLevel Level { get { return level; } set { if (value < AppSpecificSwitchLevel.Disable) { level = AppSpecificSwitchLevel.Disable; } else if (value > AppSpecificSwitchLevel.CriticalError) { level = AppSpecificSwitchLevel.CriticalError; } else { level = value; } } } // Read-only properties for the AppSpecificSwitchLevel enum public bool Disable { get { if (level <= AppSpecificSwitchLevel.Disable) { return (true); } else { return (false); } } } public bool Note { get { if (level <= AppSpecificSwitchLevel.Note) { return (true); } else { return (false); } } } public bool Warning { get { if (level <= AppSpecificSwitchLevel.Warning) { return (true); } else { return (false); } } } public bool MinorError { get { if (level <= AppSpecificSwitchLevel.MinorError) { return (true); } else { return (false); } } } public bool MediumError { get { if (level <= AppSpecificSwitchLevel.MediumError) { return (true); } else { return (false); } } } public bool CriticalError { get { if (level <= AppSpecificSwitchLevel.CriticalError) { return (true); } else { return (false); } } } }
In code, you can instantiate this custom class by invoking its constructor:
AppSpecificSwitch appSwitch = new AppSpecificSwitch("MyApplication", "My Application Specific Switch");
Set the switch in the application configuration file. For example,
the following configuration file sets the level of our custom switch
to AppSpecificSwitchLevel.CriticalLevel
:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <switches> <add name="MyApplication" value="5" /> </switches> </system.diagnostics> </configuration>
More information on configuration files can be found in Recipe 6.1 and Recipe 6.2.
The BooleanSwitch
and
TraceSwitch
classes defined in the FCL might not
always have the flexibility that you need. In these cases, you can
create a class that inherits from the Switch
class—the abstract base class of all switch type classes.
The critical part of creating a custom switch class is the
constructor. The constructor must call its base class constructor
using the :base( )
syntax. If this syntax is
omitted, a compiler error will appear indicating that there is no
default constructor to call on the base class
Switch
. You might notice that the
Switch
class contains a single public constructor
that accepts two string parameters. This is designed so that you must
use this constructor when building an object of this type or any type
derived from it. Calling the base class’s
constructor also allows the application configuration file to be
searched, if one exists, for any initialization value for this switch
object.
We can circumvent the configuration file search by writing the constructor as follows:
public AppSpecificSwitch(string displayName, string description) : base("", description) { this.Level = (AppSpecificSwitchLevel)base.SwitchSetting; }
The other item of interest in this constructor is the one line of
code in its body. This line of code grabs the level information
acquired from the application configuration file and sets this
inherited class’s Level
property
to this value. This line is required because the base class is the
one that receives the initialization information from a configuration
file, not the inherited class.
This class contains several other properties. The first is the
Level
property, which gets and sets the current
level of this object. The levels are defined in the
AppSpecificSwitchLevel
enumeration. This class
also contains a read-only property for each element in the
AppSpecificSwitchLevel
enumeration. These can be
used to query this object to determine whether its various levels are
set.
See Recipe 6.1 and Recipe 6.2; see the “Switch Class” and “Trace and Debug Settings Schema” topics in the MSDN documentation.