#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[2];
            int[] ints = (int[])arrints;

            // From array to IList<>, if explicit conversion from
            // array element type to IList type exists.
            object[] objs = new Dog[2];
            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[2];
            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,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,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,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,045 – Implicit Conversions When Assigning from a Nullable Type

Implicit conversions are allowed when converting from a value type to its associated nullable type.  Implicit conversions are not allowed in the other direction, however, from nullable type to corresponding value type.  This is because the range of the nullable type is greater than the range of the associated value type.  That is, the conversion may result in a loss of data.  You must either use an explicit conversion or access the underlying value using the Value property.

            int anInt = 12;

            // Allowed - implicit conversion to nullable type
            int? nullableInt = anInt;

            // Also allowed, since implicit conversion from int to long
            // is allowed
            long? nullableLong = anInt;

            // Implicit conversion not allowed
            //int newInt = nullableInt;

            // Must do explicit conversion
            int newInt = (int)nullableInt;

            // Better
            newInt = nullableInt.HasValue ? nullableInt.Value : 0;

            // long? = int? implicit conversion IS allowed
            nullableLong = nullableInt;

#1,025 – Converting between enum Types

You can convert between two different enum types as long as they both use the same underlying type (e.g. int).  You use an explicit cast to do the conversion.

Assuming two enum types that by default use int as their underlying type, e.g.:

    public enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
    public enum Dinner { Sausages, Mutton, Tacos, Wontons, ThinMints, FriedEggs, Sandwiches }

You can convert between them using a simple cast:

            Day today = Day.Monday;
            Dinner menuTonight = (Dinner)today;
            Console.WriteLine("Today is {0} and I'm having {1} for dinner", today, menuTonight);

1025-001