Recipe 3.15. 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 you have four different point classes:
public class Point2D {…}
public class Point3D {…}
public class ExPoint2D : Point2D {…}
public class ExPoint3D : Point3D {…}
Next, you have a method that accepts an integer value and, based on this value, one of the four specific point types is returned:
public object CreatePoint(PointTypeEnum pointType)
{
switch (pointType)
{
case PointTypeEnum.Point2D:
return (new Point2D( ));
case PointTypeEnum.Point3D:
return (new Point3D( ));
case PointTypeEnum.ExPoint2D:
return (new ExPoint2D( ));
case PointTypeEnum.ExPoint3D:
return (new ExPoint3D( ));
default:
return (null);
}
}
where the
PointTypeEnum
is defined as:
public enum PointTypeEnum
{
Point2D, Point3D, ExPoint2D, ExPoint3D
}
Finally, you 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(PointTypeEnum.Point2D);
// 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 you to differentiate between base classes and their derived classes (
ExPoint2D
derives from
Point2D
and
ExPoint3D
derives from
Point3D
). If you 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 will succeed or
false
if the cast will 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.
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 in which 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 Recipes 3.13 and 3.14; see the "( ) Operator," "as Operator," and "is Operator" topics in the MSDN documentation.
|