Casting
Remarks#
Casting is not the same as Converting. It is possible to convert the string value "-1"
to an integer value (-1
), but this must be done through library methods like Convert.ToInt32()
or Int32.Parse()
. It cannot be done using casting syntax directly.
Cast an object to a base type
Explicit Casting
If you know that a value is of a specific type, you can explicitly cast it to that type in order to use it in a context where that type is needed.
object value = -1;
int number = (int) value;
Console.WriteLine(Math.Abs(number));
If we tried passing value
directly to Math.Abs()
, we would get a compile-time exception because Math.Abs()
doesn’t have an overload that takes an object
as a parameter.
If value
could not be cast to an int
, then the second line in this example would throw an InvalidCastException
Safe Explicit Casting (as
operator)
If you aren’t sure whether a value is of the type you think it is, you can safely cast it using the as
operator. If the value is not of that type, the resulting value will be null
.
object value = "-1";
int? number = value as int?;
if(number != null)
{
Console.WriteLine(Math.Abs(number.Value));
}
Note that null
values have no type, so the as
keyword will safely yield null
when casting any null
value.
Implicit Casting
A value will automatically be cast to the appropriate type if the compiler knows that it can always be converted to that type.
int number = -1;
object value = number;
Console.WriteLine(value);
In this example, we didn’t need to use the typical explicit casting syntax because the compiler knows all int
s can be cast to object
s. In fact, we could avoid creating variables and pass -1
directly as the argument of Console.WriteLine()
that expects an object
.
Console.WriteLine(-1);
Checking compatibility without casting
If you need to know whether a value’s type extends or implements a given type, but you don’t want to actually cast it as that type, you can use the is
operator.
if(value is int)
{
Console.WriteLine(value + "is an int");
}
Explicit Numeric Conversions
Explicit casting operators can be used to perform conversions of numeric types, even though they don’t extend or implement one another.
double value = -1.1;
int number = (int) value;
Note that in cases where the destination type has less precision than the original type, precision will be lost. For example, -1.1
as a double value in the above example becomes -1
as an integer value.
Also, numeric conversions rely on compile-time types, so they won’t work if the numeric types have been “boxed” into objects.
object value = -1.1;
int number = (int) value; // throws InvalidCastException
Conversion Operators
In C#, types can define custom Conversion Operators, which allow values to be converted to and from other types using either explicit or implicit casts. For example, consider a class that is meant to represent a JavaScript expression:
public class JsExpression
{
private readonly string expression;
public JsExpression(string rawExpression)
{
this.expression = rawExpression;
}
public override string ToString()
{
return this.expression;
}
public JsExpression IsEqualTo(JsExpression other)
{
return new JsExpression("(" + this + " == " + other + ")");
}
}
If we wanted to create a JsExpression representing a comparison of two JavaScript values, we could do something like this:
JsExpression intExpression = new JsExpression("-1");
JsExpression doubleExpression = new JsExpression("-1.0");
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
But we can add some explicit conversion operators to JsExpression
, to allow a simple conversion when using explicit casting.
public static explicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static explicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = (JsExpression)(-1);
JsExpression doubleExpression = (JsExpression)(-1.0);
Console.WriteLine(intExpression.IsEqualTo(doubleExpression)); // (-1 == -1.0)
Or, we could change these operators to implicit to make the syntax much simpler.
public static implicit operator JsExpression(int value)
{
return new JsExpression(value.ToString());
}
public static implicit operator JsExpression(double value)
{
return new JsExpression(value.ToString());
}
// Usage:
JsExpression intExpression = -1;
Console.WriteLine(intExpression.IsEqualTo(-1.0)); // (-1 == -1.0)
LINQ Casting operations
Suppose you have types like the following:
interface IThing { }
class Thing : IThing { }
LINQ allows you to create a projection that changes the compile-time generic type of an IEnumerable<>
via the Enumerable.Cast<>()
and Enumerable.OfType<>()
extension methods.
IEnumerable<IThing> things = new IThing[] {new Thing()};
IEnumerable<Thing> things2 = things.Cast<Thing>();
IEnumerable<Thing> things3 = things.OfType<Thing>();
When things2
is evaluated, the Cast<>()
method will try to cast all of the values in things
into Thing
s. If it encounters a value that cannot be cast, an InvalidCastException
will be thrown.
When things3
is evaluated, the OfType<>()
method will do the same, except that if it encounters a value that cannot be cast, it will simply omit that value rather than throw an exception.
Due to the generic type of these methods, they cannot invoke Conversion Operators or perform numeric conversions.
double[] doubles = new[]{1,2,3}.Cast<double>().ToArray(); // Throws InvalidCastException
You can simply perform a cast inside a .Select()
as a workaround:
double[] doubles = new[]{1,2,3}.Select(i => (double)i).ToArray();