DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 5.1 Verifying Critical Parameters

Problem

You have a method, property, or indexer that requires the correct value or set of values to be passed in to it (e.g., cannot be null, must be within a numeric range or a set of numeric ranges, the enumeration value must be a valid value in the enumeration). If an incorrect value is passed in to the method, it must inform the application and handle the invalid value gracefully.

Solution

The parameters passed in to a public method should always be tested for correctness before they are used; however, it may be more appropriate to use Debug.Assert or even to use no tests when checking parameters to nonpublic methods. If one or more fail the test, an ArgumentException, or one of its derivatives, should be thrown to ensure that the application is notified that critical data has possibly been corrupted. (Note that an IndexOutOfRangeException could instead be thrown from within an indexer.)

When a numeric parameter that is out of a specified range is passed, the ArgumentOutOfRangeException should be thrown. The following code checks whether the numberOfItems parameter is greater than an upper bound of 100:

if (numberOfItems > 100)
{
    throw (new ArgumentOutOfRangeException("numberOfItems", numberOfItems, 
              "The number of items has exceeded the defined limits."));
}

Many parameters passed to methods may produce strange results when they are null. To prevent this from happening, test the parameters to see whether they are null. If any parameter is null, throw the ArgumentNullException. The following code checks the charToSeek char variable to see whether it is null:

if (charToSeek.Equals(null))
{
    throw (new ArgumentNullException("charToSeek", 
                "The character to seek may not be null."));
}

If a method accepts an enumeration value, a caller may pass a numeric value in lieu of an enumeration value of the parameter's type. This is dangerous since the caller can easily pass in a number that does not exist in the enumeration. To prevent this problem, test the enumeration type parameter using the static IsDefined method on the Enum class. If the parameter contains a bad value, throw the InvalidEnumArgumentException. The following code shows how to test the zooAnimals parameter, of type Animals, for a bad value:

if (!Enum.IsDefined(typeof(Animals), zooAnimals))
{
    throw (new System.ComponentModel.InvalidEnumArgumentException("zooAnimals", 
              (int)zooAnimals, typeof(Animals)));
}

There is a problem with using IsDefined with two or more enumeration values ORed together. See Recipe 4.4.

Discussion

Testing parameters in this way does not have to be done on every method. Instead, you should test the parameters that are passed in to all public methods of public classes and throw an exception only if they are in error. For nonpublic methods, you can add Debug.Assert statements to test these parameters.

Being in control of the code within your assembly makes it much easier for you to know which valid parameters, their ranges, etc., you need to pass to methods within your own assembly. Someone who is unfamiliar with your assembly has a much higher chance of passing in bad arguments to the parameters in your assembly's public interface. Therefore, you should guard against bad parameters from being passed to methods that will be used by developers other than yourself.

Note that the only exception allowing for an inner exception is ArgumentException. The more general exceptions, such as ArgumentException, were designed this way, so that the more specific exceptions, such as ArgumentNullException, can be wrapped with the more general exceptions, such as ArgumentException. This specificity gives a much clearer picture of how and where the exception occurred.

See Also

See the "ArgumentException Class" topic in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section