#1,062 – Unboxing Conversions

If you’ve converted a value-typed object to a reference-typed object by boxing it, you can later unbox the object, converting it back to a value type.  Unboxing is an explicit conversion and requires a cast operator.

Below are some examples of unboxing conversions.

public interface IArea
{
double CalcArea();
}

public struct MyPoint : IArea
{
public double X;
public double Y;

public MyPoint(double x, double y)
{
X = x;
Y = y;
}

public double CalcArea()
{
return X * Y;
}
}

static void Main(string[] args)
{
int i1 = 12;
object o = i1;  // Boxing - implicit

// Unbox from object to value type
int i2 = (int)o;  // Boxing - explicit conversion

// Unbox from dynamic
dynamic d = i1;
int i3 = (int)d;

// Boxing, implicit, creates new copy
MyPoint pt = new MyPoint(2.0, 3.0);
IArea area = pt;

// Unboxing, explicit,
// from interface to value type,
// creates new copy again
MyPoint pt2 = (MyPoint)area;

// Unbox to nullable type
int? i4 = (int?)o;
o = null;
int? i5 = (int?)o;  // also works

// Boxing, implicit, to ValueType
// (creates copy)
ValueType vty = pt;

// Unboxing, creates copy
MyPoint pt3 = (MyPoint)vty;
}

#1,061 – Explicit Reference Conversions

An explicit reference conversion is a conversion between reference types that requires a cast operator.  Explicit reference conversions are not guaranteed to succeed and require a check at run-time to determine whether the conversion is allowed.  Because the check is done at run-time, the cast operator allows the conversion at compile-time.

Here are some examples:

delegate void StringDel(string info);

static void DelMethod(string info) { }

static void Main(string[] args)
{
object o1 = new Dog("Bowser");
dynamic dyn = o1;
object o2 = new Cow("Bessie");
Dog d2 = new BorderCollie("Shep");

// From object or dynamic to ref type
Dog d = (Dog)o1;
d = dyn;

// From base class to more derived type
BorderCollie bc1 = (BorderCollie)d2;

// From base class to interface that the
// class does not implement, but that
// the actual object does implement.
// E.g. Dog does not implement IRun,
//   but BorderCollie inherits from
//   Dog and does implement IBark.
//   d2 is of type Dog, but contains
//   a BorderCollie.
IRun ir1 = (IRun)d2;

// From interface type to class that
// implements the interface
BorderCollie bc2 = (BorderCollie)ir1;

// From one interface to the other, provided
// that underlying object implements the
// target interface.
// E.g. BorderCollie implements both IRun
//   and IFetch, ir1 is of type IRun but
//   refers to a BorderCollie.  We can
//   convert from variable of type IRun
//   to one of type IFetch
IFetch if1 = (IFetch)ir1;

// From one array to another, provided that
// explicit conversion exists between element
// types.
Dog[] dogs = { new Dog("Shep"), new Dog("Kirby") };
object[] dogsAsObjs = dogs;
Dog[] dogs2 = (Dog[])dogsAsObjs;

// From System.Array to a specific array type
Array arrints = new int;
int[] ints = (int[])arrints;

// From array to IList<>, if explicit conversion from
// array element type to IList type exists.
object[] objs = new Dog;
IList<Dog> dogList = (IList<Dog>)objs;

// From IList<> to array, if explicit conversion from
// IList type to array element type exists
Dog[] objs2 = new Dog;
IList<object> dogList2 = objs2;  // implicit
Dog[] dogs3 = (Dog[])dogList2;   // explicit

// From Delegate to a specific delegate type
StringDel myDel = DelMethod;
Delegate genDel = myDel;  // implicit
StringDel myDel2 = (StringDel)genDel;  // explicit
}

#1,060 – Explicit Conversions between Nullable Types

An implicit conversion exists between two nullable types if an implicit conversion exists between the corresponding value types.  For example:

int i = 12;
long l = i;  // implicit int to long
int? i2 = 12;
long? l2 = i2;  // implicit int? to long?

Similarly, an explicit conversion exists between two nullable types if an explicit conversion exists between the corresponding value types.

long l = 12;
int i = (int)l;  // explicit long to int
long? l2 = 12;
int? i2 = (int?)l2;  // explicit long? to int?

You can also convert between a nullable and non-nullable type, either implicitly or explicitly.  An explicit conversion is required when converting from a nullable type to a non-nullable type or when an explicit conversion is required by the underlying types.

int? i3 = (int?)l;   // explicit long to int?
long l3 = (long)i3;  // explicit int? to long