DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 3.16 Determining a Variable's Type with the is Operator

Problem

A method exists that creates an object from one of several types of classes. This object is then returned as a generic object type. Based on the type of object that was initially created in the method, you want to branch to different logic.

Solution

Use the is operator. This operator returns a Boolean true or false indicating whether the cast is legal, but the cast never actually occurs.

Suppose we have four different point classes:

public class Point2D {...}
public class Point3D {...}
public class ExPoint2D : Point2D {...}
public class ExPoint3D : Point3D {...}

Next, we have a method that accepts an integer value and, based on this value, one of the four specific point types are returned:

public object CreatePoint(int pointType)
{
    switch (pointType) 
    {
        case 0:
            return (new Point2D( ));
        case 1:
            return (new Point3D( ));
        case 2:
            return (new ExPoint2D( ));
        case 3:
            return (new ExPoint3D( ));
        default:
            return (null);
    }
}

Finally, we have a method that calls the CreatePoint method. This method handles the point object type returned from the CreatePoint method based on the actual point object returned:

public void CreateAndHandlePoint( )
{
    // Create a new point object and return it
    object retObj = CreatePoint(3);

    // Handle the point object based on its actual type
    if (retObj is ExPoint2D)
    {
        Console.WriteLine("Use the ExPoint2D type");
    }
    else if (retObj is ExPoint3D)
    {
        Console.WriteLine("Use the ExPoint3D type");
    }
    else if (retObj is Point2D)
    {
        Console.WriteLine("Use the Point2D type");
    }
    else if (retObj is Point3D)
    {
        Console.WriteLine("Use the Point3D type");
    }
    else 
    {
        Console.WriteLine("Invalid point type");
    }
}

Notice that the tests for the ExPoint2D and ExPoint3D objects are performed before the tests for Point2D and Point3D. This order will allow us to differentiate between base classes and their derived classes (ExPoint2D derives from Point2D and ExPoint3D derives from Point3D). If we had reversed these tests, the test for Point2D would evaluate to true for both the Point2D class and its derivatives (ExPoint2D).

Discussion

The is operator is a fast and easy method of predetermining whether a cast will work. If the cast fails, you have saved yourself the overhead of trying the cast and handling a thrown exception. If the is operator determines that this cast can successfully be performed, all you need to do is perform the cast.

The is operator is defined as follows:

expression is type

The expression and type are defined as follows:


expression

A reference type.


Type

The type to which to cast the reference type defined by expression.

This expression returns a Boolean value: true if the cast is able to succeed or false if the cast would fail. For example:

if (SpecificObj is Base)
{
    // It is of type Base
}
else
{
    // Cannot cast SpecificObj to a Base type object
}

Never use the is operator with a user-defined conversion (either explicit or implicit). The is operator always returns false when used with these types of conversions, regardless of whether the cast can be performed.


This operator does not work with user-defined conversions (both explicit and implicit). Unlike the as operator, a compile-time error will not be displayed; instead, the is operator will always return false. This operator should never be used with user-defined conversions, since the result will always be in question. Also, unlike the as operator, the is operator will work with unboxing conversions.

The following code determines whether an unboxing operation can be performed:

// An int is passed in to this method and boxed
public void SomeMethod(object o)
{
    if (o is int)
    {
        // o can be unboxed
        // It is now possible to cast o to an int
        x = (int)o;
    }
    else
    {
        // Cannot unbox o
    }
}

This code first declares an integer variable x and boxes it into an object variable o. The is operator is then used to determine whether o can be unboxed back into the integer variable x. This is the one case where it is absolutely necessary to use is if you want to avoid an exception. You can't use as here because there is no such thing as a null int, so it cannot tell you if the unboxing fails.

See Also

See Recipe 3.14 and Recipe 3.15; see the "( ) Operator," "as Operator," and "is Operator" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section