-
Book Overview & Buying
-
Table Of Contents
Learn C# Programming
By :
Sometimes we need to convert one data type into another, and that is where type conversion comes in picture. Type conversion can be classified into several categories:
Let's explore these in detail.
For built-in numeric types, when we assign the value of a variable to one of another data type, implicit type conversion occurs if both types are compatible and the range of destination type is more than that of the source type. For example, int and float are compatible types. Therefore, we can assign an integer variable to a variable of the float type. Similarly, the double type is large enough to hold values from any other numerical type, including long and float, as shown in the following example:
int i = 10; float f = i; long l = 7195467872; double d = l;
The following table shows the implicit type conversion between numeric types in C#:
There are several things to note about implicit numeric conversions:
char, byte, and sbyte types.double and decimal; this includes no implicit conversion from decimal to double or float.For reference types, the implicit conversion is always possible between a class and one of its direct or indirect base classes or interfaces. Here is an example with an implicit conversion from string to object:
string s = "example"; object o = s;
The object type (which is an alias for System.Object) is the base class for all .NET types, including string (which is an alias for System.String). Therefore, an implicit conversion from string into object exists.
When an implicit conversion between two types is not possible because there is a risk of losing information (such as while assigning the value of a 32-bit integer to a 16-bit integer), explicit type conversion is necessary. Explicit type conversion is also called a cast. To perform casting, we need to specify the target data type in parentheses in front of the source variable.
For example, double and int are incompatible types. Consequently, we need to do an explicit type conversion between them. In the following example, we assign a double value (d) to an integer using explicit type conversion. However, while doing this conversion, the fractional part of the double variable will be truncated. Hence, the value of i will be 12:
double d = 12.34; int i = (int)d;
The following table shows the list of predefined explicit conversions between numeric types in C#:
There are several things to note about explicit numeric conversions:
OverflowException.C# statements can execute either in a checked or unchecked context, which is control either with the check and unchecked keywords or with the compiler option, -checked. When none of these are specified, the context is considered unchecked for non-constant expressions. For constant expressions, which can be evaluated at compile time, the default context is always checked. In a checked context, overflow checking is enabled for integral-type arithmetic operations and conversions. In an unchecked context, these checks are suppressed. When overflow checking is enabled and overflow occurs, the runtime throws a System.OverflowException exception.
For reference types, an explicit cast is required when you want to convert from a base class or interface into a derived class. The following example shows a cast from an object to a string value:
string s = "example"; object o = s; // implicit conversion string r = (string)o; // explicit conversion
The conversion from string into object is performed implicitly. However, the opposite requires an explicit conversion in the (string)o form, as shown in the preceding snippet.
A user-defined conversion can define an implicit or explicit conversion or both from one type into another. The type that defines these conversions must be either the source or the target type. To do so, you must use the operator keyword followed by implicit or explicit. The following example shows a type called fancyint, which defines implicit and explicit conversions from and to int:
public readonly struct fancyint
{
private readonly int value;
public fancyint(int value)
{
this.value = value;
}
public static implicit operator int(fancyint v) => v.value;
public static explicit operator fancyint(int v) => new fancyint(v);
public override string ToString() => $"{value}";
}
You can use this type as follows:
fancyint a = new fancyint(42); int i = a; // implicit conversion fancyint b = (fancyint)i; // explicit conversion
In this example, a is an object of the fancyint type. The value of a can be implicitly converted into int, because an implicit conversion operator is defined. However, the conversion from int to fancyint is defined as explicit, therefore a cast is necessary, as in (fancyint)i.
Conversion with a helper class or method is useful to convert between incompatible types, such as between a string and an integer or a System.DateTime object. There are various helper classes provided by the framework, such as the System.BitConverter class, the System.Convert class, and the Parse() and TryParse() methods of the built-in numeric types. However, you can provide your own classes and methods to convert between any types.
The following listing shows several examples of conversion using helper classes:
DateTime dt1 = DateTime.Parse("2019.08.31");
DateTime.TryParse("2019.08.31", out DateTime dt2);
int i1 = int.Parse("42"); // successful, i1 = 42
int i2 = int.Parse("42.15"); // error, throws exception
int.TryParse("42.15", out int i3); // error, returns false,
// i3 = 0
It is important to note the key difference between Parse() and TryParse(). The former tries to perform parsing and if that succeeds, it returns the parsed value; but if it fails, it throws an exception. The latter does not throw an exception, but returns bool, indicating the success or failure, and sets the second out parameter to the parsed value if successful or to the default value if it fails.