7.4. The Built-in Value Types

As mentioned earlier, all C# types inherit from the System.Object class, and therefore most of the built-in types that we will discuss have a representation in the System namespace. For example, int is a keyword that is used to represent an integer value type, and it is also represented by the System.Int32 class. The simple built-in types can be further classified as integral types, floating-point types, decimal types, and Boolean types.

Table 7.2. Built-in Integral Types (C#)
Type (Keyword)Size.NET Framework Type
sbyteSigned 8-bit integerSystem.Sbyte
byteUnsigned 8-bit integerSystem.Byte
charUnicode 16-bit characterSystem.Char
shortSigned 16-bit integerSystem.Int16
ushortUnsigned 16-bit integerSystem.Uint16
intSigned 32-bit integerSystem.Int32
uintUnsigned 32-bit integerSystem.Uint32
LongSigned 64-bit integerSystem.Int64
ulongUnsigned 64-bit integerSystem.Uint64

7.4.1. Built-in Integral Value Types

Table 7.2 shows the built-in integral types. The keyword is given along with the corresponding .NET type.

You can get the range of each of these integral types by using the MaxValue and MinValue properties on their corresponding .NET Framework class types. Consider this code:

Console.WriteLine(System.Int32.MaxValue);
Console.WriteLine(System.Int32.MinValue);

It yields the following output:

2147483647
-22147483648

Because each of the integral data type keywords has a representation as a class in the System namespace, you can actually use the new operator on these built-in types. Therefore, the following two assignments are equivalent:

int i = 0;
int i = new int();

The value assigned to the data type in the second statement is the default value of the int data type, which is 0. The next few sections explore each of the keywords shown in Table 7.2.

The sbyte and byte Keywords

The range of byte is 0 through 255, and the range of sbyte is –128 through 127. The default value for both sbyte and byte is 0. You can declare an sbyte and a byte variable this way:

byte b = new byte();
sbyte s = new sbyte();

Here, we use the default constructor of the byte and sbyte keywords. The value assigned to b and s will be the default value, which is 0. You can also use the traditional approach to assign literals to the integral variables:

sbyte mySbyte = 127;
byte mybyte = 8;

Here, the integer literal on the right will be implicitly converted to the appropriate data type on the left as long as the literal is within the (min, max) range of the data type of the left side. Because both 127 and 8 are within the (min, max) range of sbyte and byte, respectively, the implicit conversion will be successful; otherwise, a compilation error would occur. This simplifies declaring variables of type sbyte and byte because you need not explicitly cast the literals to the data type on the left. In other words, the following two statements are redundant:

sbyte mySbyte = (sbyte) 127;
byte mybyte = (byte) 8;

However, if you are passing an int literal to a method whose signature requires an sbyte or a byte, an explicit cast is required. For example, the following two overloaded methods differ only in the arguments they take:

public static void MyMethod (byte b);
public static void MyMethod (sbyte b);

To make sure the appropriate method gets called, an explicit cast of the literal is required:

MyMethod ((byte) 5);
MyMethod ((sbyte) 5);

Table 7.3. Valid Implicit Conversions for the sbyte and byte Data Types (C#)
Conversion FromConversion To
byteshort, int, long, float, double, or decimal
sbyteshort, ushort, int, uint, long, ulong, float, double, or decimal

If the explicit cast is not done, then rules of implicit conversion will take precedence. In this case, calling MyMethod(5) will call the method that takes the sbyte method argument.

Table 7.3 shows some valid implicit conversions.

You cannot implicitly convert nonliteral numeric types of larger storage size to sbyte or byte. For example:

byte x = 10, y = 10;
byte z = x + y; // Error: conversion from int to byte

The assignment statement will produce a compilation error because the arithmetic expression on the right side of the assignment operator evaluates to int by default.

The short and ushort Keywords

The C# short ranges from –32,768 through 32,767, and ushort ranges from 0 through 65,535. The default value for both short and ushort is 0. You can declare these types this way:

short x = 334;
ushort y = 10;
short s = new short();
ushort s = new ushort();

Again, there is an implicit conversion of the integer literal on the right to the short and ushort because they are within the range of the data types. When you create a short or ushort using the default constructor, the default value is assigned to the variable. You cannot implicitly convert a nonliteral data type with larger storage type to short or ushort. Therefore, the following assignment statement will produce a compilation error because the arithmetic expression on the right side of the assignment operator evaluates to int by default:

short x =5;
short y = 6;
short z = x + y; //Errors on compiling.

It is possible, though, to use the following statements, where the destination variable has the same or a larger storage size:

int m = x + y;
long n = x + y;

Table 7.4 lists the implicit conversion rules for the data types short and ushort.

Implicit conversions might occur in many situations, including method invocation and assignment statements.

The int and uint Keywords

The C# int ranges from –2,147,483,648 through 2,147,483,647, and uint ranges from 0 through 4,294,967,295. The default value for both int and uint types is 0. You can declare these types this way:

int x = 334;
uint y = 10;
int m = new int();
uint n = new uint();

Table 7.5 lists the implicit conversion rules for the data types int and uint.

To assign data types larger than an int or uint to int or uint, you must downcast the variable. For example:

Table 7.4. Valid Implicit Conversions for the ushort and short Data Types (C#)
Conversion FromConversion To
shortshort, int, long, float, double, or decimal
ushortshort, ushort, int, uint, long, ulong, float, double, or decimal

Table 7.5. Valid Implicit Conversions for the uint and int Data Types (C#)
Conversion FromConversion To
intlong, float, double, or decimal
uintlong, ulong, float, double, or decimal
sbyte, byte, short, ushort, or charint
byte, ushort, or charuint

long l = 22;
uint ui = (uint) l;

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: int, uint, long, ulong.

You can also use the suffix u or U:

uint myUint = 123U;

When you use the suffix U or u, the literal type is determined to be either uint or ulong according to its size. In this example, it is uint.

The long and ulong Keywords

The C# long ranges from –9,223,372,036,854,775,808 through 9,223,372,036,854,775,807, and the ulong ranges from 0 through 18,446,744,073,709,551,615. The default value for long and ulong is 0. You can declare this type this way:

long l = 234;
ulong m = 8676;
long j = new long();
ulong k = new ulong();

When an integer literal has no suffix, its type is the first of these types in which its value can be represented: int, uint, long, ulong. You can also use suffixes to specify the type of the literal according to the following rules:

  • If you use L or l, the type of the literal integer will be either long or ulong according to its size.

  • If you use U or u, the type of the literal integer will be either uint or ulong according to its size.

  • If you use UL, ul, Ul, uL, LU, lu, Lu, or lU, the type of the literal integer will be ulong.

Suffixes are used for clarity when you're passing parameters to overloaded methods. Adding the suffix L to the integer literal 5 calls the right method:

public void method1(long i) {}
public void method1(int i) {}
method1(5L); // will call method1(long i)

Table 7.6 lists the implicit conversion rules for the data types long and ulong.

You can use the long type with other numeric integral types in the same expression, in which case the expression is evaluated as long. For example, the following expression evaluates as long:

8809L + 876;

The char Keyword

The char keyword is used to declare a Unicode character. Unicode characters are 16-bit characters used to represent most of the known written languages in the world. A char can be implicitly converted to ushort, int, uint, long, ulong, float, double, or decimal. However, there are no implicit conversions from other types to the char type. The default value of char type is ''.

Table 7.6. Valid Implicit Conversions for the ulong and long Data Types (C#)
Conversion FromConversion To
longfloat, double, or decimal
ulongfloat, double, or decimal
sbyte, byte, short, ushort, int, uint, or charlong
byte, ushort, uint, or char to ulongulong

Table 7.7. Built-in Floating-Point Types (C#)
Type (Keyword)Range.NET Framework Type
float±1.5 × 10-45 to ±3.4 × 1038System.Single
double±5.0 × 10-324 to ±1.7 × 10308System.Double

To summarize, all integral types share some common rules. Large data types cannot be assigned to a smaller data type without explicit casting. The implicit rules stated for each of the data types are used at the time the assignment is made and parameters are passed to a method call. Certain data type literals can be suffixed with an appropriate alphabet, and this practice is highly encouraged for the sake of clarity. Data types can be constructed like regular objects.

7.4.2. The Built-in Floating-Point Types

Table 7.7 shows the built-in floating-point types. The keyword is given along with the corresponding .NET class, which is found in the System namespace.

The float Keyword

The float keyword denotes a simple type that stores 32-bit floating-point values.

By default, a real numeric literal on the right side of the assignment operator is treated as double. Therefore, to initialize a float variable, you use the suffix f or F. For example:

float x = 6.78F;

If you don't use the suffix in the preceding declaration, you will get a compilation error because you are attempting to store a double value in a float variable. You can mix numeric integral types and floating-point types in an expression. The expression is evaluated according to the following rules:

  • If one of the floating-point types is double, the expression evaluates to double.

  • If there is no double type in the expression, the expression evaluates to float.

Listing 7.3 shows how various data types are mixed with floats to yield a float result.

Listing 7.3. Mixing float Types with Other Data Types (C#)
using System;
class FloatTest {
  public static void Main() {
    int x = 3;
    float y = 10.5f;
    short z = 5;
    Console.WriteLine("Result is "+ 2.7f*(x*y/z));
  }
}

The output of Listing 7.3 is

Result is 17.01

Listing 7.4 shows some useful properties of the System.Single class.

Listing 7.4. System.Single Class Properties (C#)
using System;
class FloatTest {
  public static void Main() {
    Console.WriteLine(System.Single.Epsilon);
    Console.WriteLine(System.Single.MaxValue);
    Console.WriteLine(System.Single.MinValue);
    Console.WriteLine(System.Single.NaN);
    Console.WriteLine(System.Single.NegativeInfinity);
    Console.WriteLine(System.Single.PositiveInfinity);
  }
}

The output of Listing 7.4 is as follows:

1.401298E45
3.402823E+38
–3.402823E+38
NaN
–Infinity
Infinity

You can also instantiate a float type using the default constructor, in which case the variable takes the default value of 0.0f.

The double Keyword

The double keyword denotes a simple type that stores 64-bit floating-point values. By default, a real numeric literal on the right side of the assignment operator is treated as double. However, if you want an integer number to be treated as double, you use the suffix d or D. For example:

double x = 3d;

You can mix numeric integral types and floating-point types in an expression. The expression is evaluated such that if one of the floating-point types is double, the expression evaluates to double. You cannot assign a double to a float data type without explicitly casting.

7.4.3. The Built-in Decimal Value Types

This category has only one data type (keyword decimal). The decimal keyword denotes a 128-bit data type. Compared with floating-point types, the decimal type has a greater precision and a smaller range, and that makes it suitable for financial and monetary calculations. If you want a numeric real literal to be treated as decimal, you use the suffix m or M. For example:

decimal money = 50.5m;

Without the suffix m, the number is treated as a double, thus generating a compiler error. The decimal type is also represented by the System.Decimal class. The integral types are implicitly converted to decimal, and the result evaluates to decimal. Therefore, you can initialize a decimal variable using an integer literal without the suffix. For example:

decimal myMoney = 300;

There is no implicit conversion between floating-point types and the decimal type; therefore, a cast must be used to convert between these two types. For example:

decimal money = 109.9m;
double x = (double) money;
money = (decimal) x;

You can also mix decimal and numeric integral types in the same expression. However, mixing decimal and floating-point types without a cast results in a compilation error.

7.4.4. The Built-in Boolean Value Types

The bool keyword is an alias of System.Boolean. It is used to declare variables to store the Boolean values: true and false. You can assign a Boolean value to a bool variable. For example:

bool var = true;

You can also assign to a bool variable an expression that evaluates to bool. For example:

bool isTrue = (c >= 20);

In C++, a value of type bool can be converted to a value of type int; in other words, false is equivalent to zero, and true is equivalent to nonzero values. In C#, there is no conversion between the bool type and other types.

7.4.5. Explicit Conversions

We have described the built-in C# data types and have explained the implicit conversion rules that apply to them. Implicit conversions occur during assignment or when the literal is passed a method parameter. By contrast, explicit numeric conversion is used to convert any numeric type to any other numeric type for which there is no implicit conversion; explicit numeric conversion uses a cast expression. Table 7.8 shows the explicit conversion rules for the various data types.

Table 7.8. Explicit Numeric Conversion Rules (C#)
Converted FromConverted To
sbytebyte, ushort, uint, ulong, or char
bytesbyte or char
shortsbyte, byte, ushort, uint, ulong, or char
ushortsbyte, byte, short, or char
intsbyte, byte, short, ushort, uint, ulong, or char
uintsbyte, byte, short, ushort, int, or char
longsbyte, byte, short, ushort, int, uint, ulong, or char
ulongsbyte, byte, short, ushort, int, uint, long, or char
charsbyte, byte, or short
floatsbyte, byte, short, ushort, int, uint, long, ulong, char, or decimal
doublesbyte, byte, short, ushort, int, uint, long, ulong, char, float, or decimal
decimalsbyte, byte, short, ushort, int, uint, long, ulong, char, float, or double

The next section looks at the reference types in C#.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.4.181