Type conversion is a process of converting one type into another. Using C# type conversion techniques, not only can you convert data types but you can also convert object types. The type conversion in C# can be either implicit conversion or an explicit conversion. If one type of data is automatically converted into another type of data, it is known as implicit conversion. There is no data loss due to implicit conversion. But explicit conversion is a forced conversion and there may be a data loss. Type conversions occur mainly when we pass arguments to a function or mixing mode arithmetic etc.
Implicit Conversions in C#
The implicit conversions can occur in a variety of situations like function invoking, cast expressions, assignments etc. The implicit conversions can be further classified into different categories.
Implicit Numerical Conversions
The possible implicit numerical conversions in C# are shown below.
The implicit conversions in the direction of the arrow are possible with basic data types of C#. Remember that there are no implicit conversions to the char type from any other types. Also, there are no implicit or explicit conversions associated with the bool type. The examples of implicit numerical conversions are shown below.
- long x;
- int y = 25;
- x = y;
Implicit Enumeration Conversion
An implicit enumeration conversion permits the decimal integer literal 0 to be converted to an enum type.
Implicit Reference Conversion
The possible implicit reference conversions are:
- From any reference type to object.
- From any class type D to any class type B, provided D is inherited from B.
- From any class type A to interface type I, provided A implements I.
- From any interface type I2 to any other interface type I1, provided I2 inherits I1.
- From any array type to System.Array.
- From any array type A with element type a to an array type B with element type b provided A & B differ only in element type (but the same number of elements) and both a and b are reference types and an implicit reference conversion exists between a & b.
- From any delegate type to System.Delegate type.
- From an array type or delegate type to System.ICloneable.
- From null type to any reference type.
Boxing Conversions
Boxing is the conversion of any value type to object type. Remember that boxing is an implicit conversion. Boxing a value of value type like int consists of allocating an object instance and copying the value of the value type into that object instance. An example of boxing is shown below.
- int x = 10;
- object o = x;
- if(o is int)
- Console.WriteLine("o contains int type");
A boxing conversion is making a copy of the value being boxed. But when we convert a reference type to object type, the object continues to reference the same instance.
Explicit Conversions in C#
The explicit conversions are forced conversions in C# by using the casting operator (). There may be data loss due to explicit conversions. For example when we explicitly convert a double type to an int type as shown below:
- int x = (int) 26.45;
- Console.WriteLine(x);
Explicit Numerical Conversions
They are the conversions from a numeric type to another numeric type for which an implicit conversion doesn't already exist. It is possible to convert any numerical type to any other numerical type explicitly. The explicit numerical conversions can result in possibly a data loss or OverflowException to be thrown.
Explicit Enumeration Conversions
The explicit enumeration conversions are,
- From sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double or decimal to any enum type.
- From any enum type to sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double or decimal.
- From any enum type to any other enum type.
Explicit Reference Conversions
The possible explicit reference conversions are,
- From object to any reference type.
- From any class type B to any class type D, provided B is the base class of D
- From any class type A to any interface type I provided S is not sealed and do not implement I.
- From any interface type I to any class type A provided A is not sealed and implement I.
- From any interface type I2 to any interface type I1, provided I2 is not derived from I1.
- From System.Array to an array type.
- From System.Delegate type to any delegate type.
- From System.ICloneable to any array or delegate type.
For any reason, if an explicit reference conversion fails, an InvalidCastException is thrown.
Un-boxing Conversions
Un-boxing is the conversion of an object type to a value type. The casting operator () is necessary for unboxing. The example of unboxing is shown below.
- int x = 100;
- object o = x;
- int I (int) o;
For an unboxing conversion to a given value type to succeed at run-time, the value type of the source argument must be reference type to an object that was previously created by boxing a value of the value type. If the source argument is null or a reference type to an incompatible type, an InvalidCastException is thrown.
User-Defined Conversions
Whatever we explained so far are the conversions (implicit or explicit) among the basic data types or among the same user-defined data types. Suppose, we have to do conversions between basic data types and user-defined data types or between two incompatible user-defined data types. C# provides a facility to define conversion operators inside a class or struct to achieve this.
But C# provides only certain user-defined conversions to be defined. In particular, it is not possible to redefine an existing implicit or explicit conversion in C#. A class or struct is permitted to declare a conversion function from a source type S to a target type T only if all of the following are true,
- Both S & T are different types.
- Either S or T is a class or struct type in which the operator declaration takes place.
- Neither S nor T is an object type or an interface type.
- T is not a base class of S or S is not a base class of T.
The user-defined conversion can either implicit or explicit. The general form of user-defined conversion operator is as follows,
- public static implicit/explicit operator type (arguments)
- {
- }
Where the operator is the required keyword and type is the required return type, remember that operator function should be public and static and there is no return type. The presence of the explicit keyword makes the conversion as explicit and implicit keyword makes the conversion as implicit.
The conversion operator can be defined either inside the class or struct type. Remember that user-defined conversions are not allowed to convert from or to interface types. Also note that since explicit or implicit keywords are not part of the method's signature, it is not possible to declare both explicit and implicit conversion operator with the same source and target type.
An example of a user-defined conversion is shown below.
-
-
- using System;
- class MyDigit {
- private int x;
- public MyDigit() {}
- public MyDigit(int i) {
- x = i;
- }
- public void ShowDigit {
- Console.WriteLine("{0}", x);
- }
- public static implicit operator int(MyDigit md) {
- return md.x;
- }
- public static explicit operator MyDigit(int val) {
- return new MyDigit(val);
- }
- }
- class MyClient {
- public static void Main() {
- MyDigit md1 = new MyDigit1(10);
- int x = md1;
- Console.WriteLine(x);
- int y = 25;
- MyDigit md2 = (MyDigit) y;
- Console.WriteLine(md2.ShowDigit());
- }
- }
The above example converts a basic type to a class type and a class type to basic type by using the conversion operator. The conversion operator can be used to convert one class type to another also. An example is shown below.
-
-
- using System;
- class MyClass1 {
- public int x;
- public MyClass1(int a) {
- x = a;
- }
- public void Show1() {
- Console.WriteLine(x);
- }
- public static explicit operator MyClass2(MyClass1 mc1) {
- MyClass2 mc2 = new MyClass2(mc1.x * 10, mc1.x * 20);
- return mc2;
- }
- }
- class MyClass2 {
- public float x, y;
- public MyClass2(float a, float b) {
- x = a;
- y = b;
- }
- public void Show2() {
- Console.WriteLine(x);
- Console.WriteLine(y);
- }
- }
- class MyClient {
- public static void Main() {
- MyClass1 mc1 = new MyClass1(100);
- mc1.Show1();
- MyClass2 mc2 = (MyClass2) mc1;
- mc2.Show2();
- }
- }
If a user-defined conversion can give rise to exceptions or loss of information, then that conversion should be defined as an explicit conversion. In general user defined implicit conversions should be designed to never throw exceptions and never lose information. Remember that user defined conversions can be either defined inside source class or inside a target class in the case of class-to-class conversions.