#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

#1,059 – Converting from Numeric to Enumerated Types

You can convert from a numeric type to an enumerated type using the cast operator.  For example, to convert from numeric constants to an enum, we can do the following:

        public enum Weekday
        {
            Sunday = 1,
            Monday,     // 2
            Tuesday,    // 3, etc.
            Wednesday,
            Thursday,
            Friday,
            Saturday
        };

        static void Main(string[] args)
        {
            Weekday day = (Weekday)5;  // Thursday
            Console.WriteLine(day.ToString());  // "Thursday"

            Weekday day2 = (Weekday)8;    // Works!
            Console.WriteLine(day2.ToString());  // Just "8"
        }

Notice that the cast works even if there is not a defined enumerated value that matches the specified type. We can store a value of 8 in a Weekday type even though we didn’t define a Weekday with a value of 8.

1059-001

#1,058 – Custom Implicit Conversions in Both Directions

When you define a custom implicit (or explicit) conversion, you can define a conversion both to and from a particular type.

In the example below, we define custom implicit conversions that allow implicitly converting from an int to a Dog, as well as converting from a Dog to an int.

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        // Implicitly convert from int to Dog
        public static implicit operator Dog(int value)
        {
            return new Dog(string.Format("Dog-" + value.ToString()), value);
        }

        // And implicitly convert from Dog to int
        public static implicit operator int(Dog d)
        {
            return d.Age;
        }
    }

With these conversions, we can now do the following:

            // int to Dog
            int i1 = 12;
            Dog dog1 = i1;

            // Dog to int
            Dog dog2 = new Dog("Bowser", 5);
            int i2 = dog2;

1058-001

#1,057 – Custom Explicit Conversions

You can define both implicit and explicit custom conversions for a type that you author.

In the code fragment below, we’ve defined an implicit conversion from int to Dog and an explicit conversion from Cow to Dog.

        // Implicitly convert from int to Dog
        public static implicit operator Dog(int value)
        {
            return new Dog(string.Format("Dog-" + value.ToString()), value);
        }

        // Explicitly convert from Cow to Dog
        public static explicit operator Dog(Cow cow)
        {
            return new Dog(string.Format(cow.Name + " IWasACow"), cow.Age);
        }

We can now do the following:

            Cow someCow = new Cow("Bessie", 3);

            // Implicit conversion from int to Dog
            Dog anotherDog = 42;

            // Explicit conversion from Cow to Dog
            Dog nowADog = (Dog)someCow;

If we try assigning a Cow instance to a variable of type Dog without the cast operator, we’ll get a compile-time error indicating that there is no implicit conversion between Cow and Dog.

1057-001

#1,056 – Custom Implicit Conversions between Reference Types

You can define your own implicit conversions between value types.  You can also define a custom implicit conversion to allow implicitly converting from any type to a given reference type.

In the example below, we add methods to a Dog type to allow implicit conversions from both Cow and int types to the Dog type.

        // Implicitly convert from Cow to Dog
        public static implicit operator Dog(Cow cow)
        {
            return new Dog(string.Format(cow.Name + " IWasACow"), cow.Age);
        }

        // Implicitly convert from int to Dog
        public static implicit operator Dog(int value)
        {
            return new Dog(string.Format("Dog-" + value.ToString()), value);
        }

We can now do the following implicit conversions:

            Cow someCow = new Cow("Bessie", 3);

            // Cow becomes Dog
            Dog nowADog = someCow;

            // Number 42 becomes Dog
            Dog anotherDog = 42;

1056-001

#1,055 – Defining Your Own Implicit Conversions

Suppose that you define a new value type, for example the TimedInteger type shown below.

    public struct TimedInteger
    {
        private int theInt;
        private DateTime whenCreated;

        public TimedInteger(int value)
        {
            theInt = value;
            whenCreated = DateTime.Now;
        }
    }

You can now create instances of this type as follows:

            TimedInteger ti = new TimedInteger(5);

You can’t directly assign an integer to a variable of type TimedInteger because no implicit conversion exists between an integer literal and your type.  (Between an int and your type).
1055-001

To allow this assignment, you can define a custom implicit conversion for your type.  The code below allows an implicit conversion from an int to a TimedInteger.

        public static implicit operator TimedInteger(int value)
        {
            return new TimedInteger(value);
        }

You can now directly assign an integer literal, because there is an implicit conversion between int and TimedInteger.

            TimedInteger ti = 5;

1055-002

#1,054 – Implicit Conversions from Constant Expressions

A constant expression is an expression whose type and value can be determined at compile-time.  Integer literals are one form of a constant expression, with the type inferred based on the value of the literal (and the use of u and/or suffixes).

Recall that implicit numeric conversions are not allowed if the full range of values in the expression is not allowed in the target type.  For example, you can’t do an implicit conversion from a variable of type int to a byte, even if the variable contains a value that could be stored in a byte.

            int i = 1;

            // Implicit conversion not allowed,
            // i.e. requires a cast
            byte b = i;

Implicit conversions from constant expressions, however, are allowed as long as the value is within the range of the target type. Since the compiler knows the value at compile-time, it can make this determination.

For example, an integer literal whose value of 1 will be of type int, but is implicitly convertible to a variable of type byte.

            // Literal 1 is of type
            // int (inferred by compiler),
            // but can be implicitly converted
            // to byte.
            byte b2 = 1;

#1,053 – Implicit Conversion from Type dynamic

You can implicitly convert from an expression of type dynamic to any other type.  What this means is that the compiler allows an implicit conversion (no cast operator) from the dynamic type to any other type and compilation succeeds.

While the conversion will always succeed at compile time, the actual assignment operation may fail at run-time, depending on whether a conversion between the actual type of the dynamic object and the target type succeeds.  The dynamic keyword tells the compiler, “wait until run-time to figure out the type”.

For example:

            dynamic dyn1 = "a string";
            dynamic dyn2 = 42;

            // Everything below succeeds at compile-time
            string s = dyn1;
            int i = dyn1;      // Fails at run-time (RuntimeBinderException)

            // (NOTE: Comment out above line to get
            //  past exception).
            s = dyn2;          // Fails at run-time (RuntimeBinderException)
            i = dyn2;

#1,052 – Boxing Is a Kind of Implicit Conversion

Boxing is the process of copying a value-typed object to a new instance of a reference-typed object.  Boxing operations are classified as implicit conversions, in that you are converting between types in a way that is guaranteed to succeed and does not require a cast operator.

Below are some examples of boxing operations.

        public interface IDistance
        {
            double CalcDistance();
        }

        public struct Point3D : IDistance
        {
            public double X, Y, Z;

            public double CalcDistance()
            {
                return Math.Sqrt(X*X + Y*Y + Z*Z);
            }
        }

        public enum Mood { Crabby, NotSoCrabby };

        static void Main(string[] args)
        {
            // Three kinds of value-typed objects
            Point3D pt;
            pt.X = 1.0;
            pt.Y = 2.0;
            pt.Z = 3.0;

            int i1 = 12;
            int? i2 = null;

            // Convert to object
            object o = pt;
            o = i1;
            o = i2;

            // Convert to dynamic
            dynamic dyn1 = pt;
            dyn1 = i1;
            dyn1 = i2;

            // Convert to System.ValueType
            ValueType vty = pt;
            vty = i1;
            vty = i2;

            // Convert to interface implemented
            // by the value type
            IDistance idist = pt;
            double dist = idist.CalcDistance();

            // From enum value to System.Enum
            Mood myMood = Mood.NotSoCrabby;
            Enum genEnum = myMood;
        }

#1,051 – Implicit Reference Conversions

An implicit reference conversion is a conversion between reference types that is guaranteed to succeed and therefore does not require a cast operator.

Here are some examples:

            Dog dog = new Dog("Bowser");

            // From ref type to object
            object o1 = dog;

            // From ref type to dynamic
            dynamic dyn1 = dog;

            // From derived class to parent class
            Terrier terr = new Terrier("Jack");
            dog = terr;

            // From class to interface that class
            // implements
            IBark iBark = dog;

            // From a derived interface to
            // base interface
            IBarkWithStyle iBarkDerived = dog;
            iBark = iBarkDerived;

            // Covariant array conversion
            // Dog[] = Terrier[] ok because
            //    Dog = Terrier ok
            Terrier[] terriers = new Terrier[2];
            terriers[0] = new Terrier("Bobby");
            terriers[1] = new Terrier("Sydney");
            Dog[] dogs = terriers;

            // From array type to System.Array
            Array arr = terriers;

            // From array to IList<T>
            IList<Dog> dogList = terriers;

            // From any delegate-type to System.Delegate 
            // and the interfaces it implements
            MyStringHandlerDelegate del1 = HandleString;
            Delegate del2 = del1;

            // From null literal to any reference type
            Dog dog2 = null;

            // From any ref type to a ref type T if it has an 
            // implicit identity or reference conversion
            // to T0 and T0 has identity conversion to T.
            // E.g. can convert from Dog to object and
            //      from List to IEnumerable, so we can:
            List<Dog> somedogs = new List<Dog>();
            IEnumerable<object> genlist = somedogs;