DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 6.3 Creating Your Own Custom Switch Class

Problem

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:

Disable
MinorError
Note
MediumError
Warning
CriticalError

Solution

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:

  1. 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
    }
  2. 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);
                }
            }
        }
    }
  3. In code, you can instantiate this custom class by invoking its constructor:

    AppSpecificSwitch appSwitch = new AppSpecificSwitch("MyApplication", 
                                  "My Application Specific Switch");
  4. 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.

Discussion

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 Also

See Recipe 6.1 and Recipe 6.2; see the "Switch Class" and "Trace and Debug Settings Schema" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section