Subscribe

RSS Feed (xml)

Showing posts with label Type conversion. Show all posts
Showing posts with label Type conversion. Show all posts

Type Conversion of Expressions in C#

In addition to occurring within an assignment, type conversions also take place within an expression. In an expression, you can freely mix two or more different types of data as long as they are compatible with each other. For example, you can mix short and long within an expression because they are both numeric types. When different types of data are mixed within an expression, they are converted to the same type, on an operation-by-operation basis.
The conversions are accomplished through the use of C#’s type promotion rules. Here is the algorithm that they define for binary operations:

  • IF one operand is a decimal, THEN the other operand is promoted to decimal (unless it is of type float or double, in which case an error results).

  • ELSE IF one operand is a double, the second is promoted to double.

  • ELSE IF one operand is a float, the second is promoted to float.

  • ELSE IF one operand is a ulong, the second is promoted to ulong (unless it is of type sbyte, short, int, or long, in which case an error results).

  • ELSE IF one operand is a long, the second is promoted to long.

  • ELSE IF one operand is a uint and the second is of type sbyte, short, or int, both are promoted to long.

  • ELSE IF one operand is a uint, the second is promoted to uint.

  • ELSE both operands are promoted to int.
There are a couple of important points to be made about the type promotion rules. First, not all types can be mixed in an expression. Specifically, there is no implicit conversion from float or double to decimal, and it is not possible to mix ulong with any signed integer type. To mix these types requires the use of an explicit cast.
Second, pay special attention to the last rule. It states that if none of the preceding rules applies, then all other operands are promoted to int. Therefore, in an expression, all char, sbyte, byte, ushort, and short values are promoted to int for the purposes of calculation. This is called integer promotion. It also means that the outcome of all arithmetic operations will be no smaller than int.
It is important to understand that type promotions only apply to the values operated upon when an expression is evaluated. For example, if the value of a byte variable is promoted to int inside an expression, outside the expression, the variable is still a byte. Type promotion only affects the evaluation of an expression.
Type promotion can, however, lead to somewhat unexpected results. For example, when an arithmetic operation involves two byte values, the following sequence occurs. First, the byte operands are promoted to int. Then the operation takes place, yielding an int result. Thus, the outcome of an operation involving two byte values will be an int. This is not what you might intuitively expect. Consider the following program:
// A promotion surprise!

using System;

class PromDemo {
public static void Main() {
byte b;

b = 10;
b = (byte) (b * b); // cast needed!!

Console.WriteLine("b: "+ b);
}
}
Somewhat counterintuitively, a cast to byte is needed when assigning b * b back to b! The reason is because in b * b, the value of b is promoted to int when the expression is evaluated. Thus, b * b results in an int value, which cannot be assigned to a byte variable without a cast. Keep this in mind if you get unexpected type-incompatibility error messages on expressions that would otherwise seem perfectly OK.
This same sort of situation also occurs when performing operations on chars. For example, in the following fragment, the cast back to char is needed because of the promotion of ch1 and ch2 to int within the expression
char ch1 = 'a', ch2 = 'b';

ch1 = (char) (ch1 + ch2);
Without the cast, the result of adding ch1 to ch2 would be int, which can’t be assigned to a char.
Type promotions also occur when a unary operation, such as the unary , takes place. For the unary operations, operands smaller than int (byte, sbyte, short, and ushort) are promoted to int. Also, a char operand is converted to int. Furthermore, if a uint value is negated, it is promoted to long.

Using Casts in Expressions

A cast can be applied to a specific portion of a larger expression. This gives you fine-grained control over the way type conversions occur when an expression is evaluated. For example, consider the following program. It displays the square roots of the numbers from 1 to 10. It also displays the whole number portion and the fractional part of each result, separately. To do so, it uses a cast to convert the result of Math.Sqrt( ) to int.
// Using casts in an expression.

using System;

class CastExpr {
public static void Main() {
double n;

for(n = 1.0; n <= 10; n++) {       Console.WriteLine("The square root of {0} is {1}",                         n, Math.Sqrt(n));        Console.WriteLine("Whole number part: {0}" ,                         (int) Math.Sqrt(n));        Console.WriteLine("Fractional part: {0}",                         Math.Sqrt(n) - (int) Math.Sqrt(n) );       Console.WriteLine();    }   } }
Here is the output from the program:
The square root of 1 is 1
Whole number part: 1
Fractional part: 0
The square root of 2 is 1.4142135623731
Whole number part: 1
Fractional part: 0.414213562373095

The square root of 3 is 1.73205080756888
Whole number part: 1
Fractional part: 0.732050807568877

The square root of 4 is 2
Whole number part: 2
Fractional part: 0

The square root of 5 is 2.23606797749979
Whole number part: 2
Fractional part: 0.23606797749979

The square root of 6 is 2.44948974278318
Whole number part: 2
Fractional part: 0.449489742783178

The square root of 7 is 2.64575131106459
Whole number part: 2
Fractional part: 0.645751311064591

The square root of 8 is 2.82842712474619
Whole number part: 2
Fractional part: 0.82842712474619

The square root of 9 is 3
Whole number part: 3
Fractional part: 0

The square root of 10 is 3.16227766016838
Whole number part: 3
Fractional part: 0.16227766016838
As the output shows, the cast of Math.Sqrt( ) to int results in the whole number component of the value. In this expression:
Math.Sqrt(n) - (int) Math.Sqrt(n)
the cast to int obtains the whole number component, which is then subtracted from the complete value, yielding the fractional component. Thus, the outcome of the expression is double. Only the value of the second call to Math.Sqrt( ) is cast to int. (The slight discrepancies in the fractional parts are due to rounding errors.)

C# Type Conversion and Casting

In programming, it is common to assign one type of variable to another. For example, you might want to assign an int value to a float variable, as shown here:

int i;
float f;

i = 10;
f = i; // assign an int to a float

When compatible types are mixed in an assignment, the value of the right side is automatically converted to the type of the left side. Thus, in the preceding fragment, the value in i is converted into a float and then assigned to f. However, because of C#’s strict type-checking, not all types are compatible, and thus, not all type conversions are implicitly allowed. For example, bool and int are not compatible. Fortunately, it is still possible to obtain a conversion between incompatible types by using a cast. A cast performs an explicit type conversion. Both automatic type conversion and casting are examined here.

Automatic Conversions

When one type of data is assigned to another type of variable, an automatic type conversion will take place if

  • The two types are compatible.

  • The destination type has a range that is greater than the source type.

When these two conditions are met, a widening conversion takes place. For example, the int type is always large enough to hold all valid byte values, and both int and byte are integer types, so an automatic conversion can be applied. An automatic type conversion is also called an implicit conversion.

For widening conversions, the numeric types, including integer and floating-point types, are compatible with each other. For example, the following program is perfectly valid since long to double is a widening conversion that is automatically performed.

// Demonstrate automatic conversion from long to double.

using System;

class LtoD {
 public static void Main() {
   long L;
   double D;

   L = 100123285L;
   D = L;

   Console.WriteLine("L and D: " + L + " " + D);
 }
}

Although there is an automatic conversion from long to double, there is no automatic conversion from double to long since this is not a widening conversion. Thus, the following version of the preceding program is invalid:

// *** This program will not compile. ***

using System;

class LtoD {
 public static void Main() {
   long L;
   double D;

   D = 100123285.0;
   L = D; // Illegal!!!

   Console.WriteLine("L and D: " + L + " " + D);

 }
}

In addition to the restrictions just described, there are no automatic conversions between decimal and float or double, or from the numeric types to char or bool. Also, char and bool are not compatible with each other.

Casting Incompatible Types

Although the automatic type conversions are helpful, they will not fulfill all programming needs, because they apply only to widening conversions between compatible types. For all other cases, you must employ a cast. A cast is an instruction to the compiler to convert one type into another. Thus, it requests an explicit type conversion. A cast has this general form:

(target-type) expression 

Here, target-type specifies the desired type to convert the specified expression to. For example, if you want the type of the expression x/y to be int, you can write

double x, y;
// ...
int i = (int) (x / y) ;

Here, even though x and y are of type double, the cast converts the outcome of the expression to int. The parentheses surrounding x / y are necessary. Otherwise, the cast to int would apply only to the x, and not to the outcome of the division. The cast is necessary here because there is no automatic conversion from double to int.

When a cast involves a narrowing conversion, information might be lost. For example, when casting a long into an int, information will be lost if the long’s value is greater than the range of an int, because its high-order bits are removed. When a floating-point value is cast to an integer type, the fractional component will also be lost due to truncation. For example, if the value 1.23 is assigned to an integer, the resulting value will simply be 1. The 0.23 is lost.

The following program demonstrates some type conversions that require casts. It also shows some situations in which the casts cause data to be lost.

// Demonstrate casting.

using System;

class CastDemo {
 public static void Main() {
   double x, y;
   byte b;
   int i;
   char ch;
   uint u;
   short s;
   long l;

   x = 10.0;
   y = 3.0;
   // cast an int into a double
   i = (int) (x / y); // cast double to int, fractional component lost
   Console.WriteLine("Integer outcome of x / y: " + i);
   Console.WriteLine();

   // cast an int into a byte, no data lost
   i = 255;
   b = (byte) i;
   Console.WriteLine("b after assigning 255: " + b +
                     " -- no data lost.");

   // cast an int into a byte, data lost
   i = 257;
   b = (byte) i;
   Console.WriteLine("b after assigning 257: " + b +
                     " -- data lost.");
   Console.WriteLine();

   // cast a uint into a short, no data lost
   u = 32000;
   s = (short) u;
   Console.WriteLine("s after assigning 32000: " + s +
                     " -- no data lost.");

   // cast a uint into a short, data lost
   u = 64000;
   s = (short) u;
   Console.WriteLine("s after assigning 64000: " + s +
                     " -- data lost.");
   Console.WriteLine();

   // cast a long into a uint, no data lost
   l = 64000;
   u = (uint) l;
   Console.WriteLine("u after assigning 64000: " + u +
                     " -- no data lost.");

   // cast a long into a uint, data lost
   l = -12;
   u = (uint) l;
   Console.WriteLine("u after assigning -12: " + u +
                     " -- data lost.");
   Console.WriteLine();

   // cast an int into a char
   b = 88; // ASCII code for X
   ch = (char) b;
   Console.WriteLine("ch after assigning 88: " + ch);
 }
}

The output from the program is shown here:

Integer outcome of x / y: 3

b after assigning 255: 255 -- no data lost.
b after assigning 257: 1 -- data lost.

s after assigning 32000: 32000 -- no data lost.
s after assigning 64000: -1536 -- data lost.

u after assigning 64000: 64000 -- no data lost.
u after assigning -12: 4294967284 -- data lost.

ch after assigning 88: X

Let’s look at each assignment. The cast of (x / y) to int results in the truncation of the fractional component, and information is lost.

No loss of information occurs when b is assigned the value 255 because a byte can hold the value 255. However, when the attempt is made to assign b the value 257, information loss occurs because 257 exceeds a byte’s range. In both cases the casts are needed because there is no automatic conversion from int to byte.

When the short variable s is assigned the value 32,000 through the uint variable u, no data is lost because a short can hold the value 32,000. However, in the next assignment, u has the value 64,000, which is outside the range of a short, and data is lost. In both cases the casts are needed because there is no automatic conversion from uint to short.

Next, u is assigned the value 64,000 through the long variable l. In this case, no data is lost because 64,000 is within the range of a uint. However, when the value 12 is assigned to u, data is lost because a uint cannot hold negative numbers. In both cases the casts are needed because there is no automatic conversion from long to uint.

Finally, no information is lost, but a cast is needed when assigning a byte value to a char.

LocalsAdda.com-Variety In Web World

Fun Mail - Fun in the Mail