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.
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
).
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
istype
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 Recipe 3.14 and Recipe 3.15; see the “( ) Operator,” “as Operator,” and “is Operator” topics in the MSDN documentation.