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 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.)
No comments:
Post a Comment