C# Primitive Data Types

C# Primitive Data Types

C# Primitive Type

FCL Data Type




Ultimate base type of all other types.



A sequence of Unicode characters.



Precise decimal with 28 significant digits.



A value represented as true or false.



A 16-bit Unicode character.



8-bit unsigned integral type.



8-bit signed integral type.



16-bit signed integral type.



32-bit signed integral type.



64-bit signed integral type.



16-bit unsigned integral type.



32-bit unsigned integral type.



64-bit unsigned integral type.

single (float)


Single-precision floating-point type.



Double-precision floating-point type.

As the table shows, primitives map directly to types in the base class library and can be used interchangeably. Consider these statements:

System.Int32 age = new System.Int32(17);

int age = 17; 

System.Int32 age = 17;

They all generate exactly the same Intermediate Language (IL) code. The shorter version relies on C# providing the keyword int as an alias for the System.Int32 type. C# performs aliasing for all primitives.

Here are a few points to keep in mind when working with primitives:

  • The keywords that identify the value type primitives (such as int) are actually aliases for an underlying structure (struct type in C#). Special members of these structures can be used to manipulate the primitives. For example, the Int32 structure has a field that returns the largest 32-bit integer and a method that converts a numeric string to an integer value:

    int iMax = int.MaxValue;     // Return largest integer 
    int pVal = int.Parse("100"); // converts string to int

    The C# compiler supports implicit conversions if the conversion is a "safe" conversion that results in no loss of data. This occurs when the target of the conversion has a greater precision than the object being converted, and is called a widening conversion. In the case of a narrowing conversion, where the target has less precision, the conversion must have explicit casting. Casting is used to coerce, or convert, a value of one type into that of another. This is done syntactically by placing the target data type in parentheses in front of the value being converted: int i = (int)y;.

    short i16 = 50;    // 16-bit integer
    int i32 = i16;     // Okay: int has greater precision
    i16 = i32;         // Fails: short is 16 bit, int is 32
    i16 = (short) i32; // Okay since casting used

  • Literal values assigned to the types float, double, and decimal require that their value include a trailing letter: float requires F or f; double has an optional D or d; and decimal requires M or m.

    decimal pct = .15M; // M is required for literal value

The remainder of this section offers an overview of the most useful primitives with the exception of string, which is discussed later in the chapter.


The decimal type is a 128-bit high-precision floating-point number. It provides 28 decimal digits of precision and is used in financial calculations where rounding cannot be tolerated. This example illustrates three of the many methods available to decimal type. Also observe that when assigning a literal value to a decimal type, the M suffix must be used.

decimal iRate = 3.9834M;         // decimal requires M 

iRate = decimal.Round(iRate,2);  // Returns 3.98

decimal dividend = 512.0M;

decimal divisor = 51.0M;

decimal p = decimal.Parse("100.05");

// Next statement returns remainder = 2

decimal rem = decimal.Remainder(dividend,divisor);


The only possible values of a bool type are true and false. It is not possible to cast a bool value to an integer—for example, convert true to a 1, or to cast a 1 or 0 to a bool.

bool bt = true;

string bStr = bt.ToString(); // returns "true"

bt = (bool) 1;               // fails


The char type represents a 16-bit Unicode character and is implemented as an unsigned integer. A char type accepts a variety of assignments: a character value placed between individual quote marks (' '); a casted numeric value; or an escape sequence. As the example illustrates, char also has a number of useful methods provided by the System.Char structure:

myChar =  'B';       // 'B' has an ASCII value of 66

myChar = (char) 66;  // Equivalent to 'B'

myChar = '\u0042';   // Unicode escape sequence

myChar = '\x0042';   // Hex escape sequence

myChar = '\t';       // Simple esc sequence:horizontal tab

bool bt;

string pattern = "123abcd?";

myChar = pattern[0];                  // '1'

bt = char.IsLetter(pattern,3);        // true  ('a')

bt = char.IsNumber(pattern,3);        // false

bt = char.IsLower(pattern,0);         // false ('1')

bt = char.IsPunctuation(pattern,7);   // true  ('?')

bt = char.IsLetterOrDigit(pattern,1); // true

bt = char.IsNumber(pattern,2);        // true  ('3')

string kstr="K";

char k = char.Parse(kstr);

byte, sbyte

A byte is an 8-bit unsigned integer with a value from 0 to 255. An sbyte is an 8-bit signed integer with a value from –128 to 127.

byte[] b = {0x00, 0x12, 0x34, 0x56, 0xAA, 0x55, 0xFF};

string s = b[4].ToString(); // returns 170

char myChar = (char) b[3];

short, int, long

These represent 16-, 32-, and 64-bit signed integer values, respectively. The unsigned versions are also available (ushort, uint, ulong).

short i16 = 200;

i16 = 0xC8 ;     // hex value for 200

int i32 = i16;   // no casting required 

single, double

These are represented in 32-bit single-precision and 64-bit double-precision formats. In .NET 1.x, single is referred to as float.

  • The single type has a value range of 1.5 x 10 –45 to 3.4 x 1038 with 7-decimal digit precision.

  • The double type has a value range of 5 x 10–324 to 1.7 x 10308 with 15- to 16-decimal digit precision.

  • Floating-point operations return NaN (Not a Number) to signal that the result of the operation is undefined. For example, dividing 0.0 by 0.0 results in NaN.

  • Use the System.Convert method when converting floating-point numbers to another type.

float xFloat = 24567.66F;

int xInt = Convert.ToInt32(xFloat);  // returns 24567

int xInt2 = (int) xFloat;

if(xInt == xInt2) {  }               // False

string xStr = Convert.ToString(xFloat);

single zero = 0;

if (Single.IsNaN(0 / zero)) {  }     // True

double xDouble = 124.56D;

Note that the F suffix is used when assigning a literal value to a single type, and D is optional for a double type.

Using Parse and TryParse to Convert a Numeric String

The primitive numeric types include Parse and tryParse methods that are used to convert a string of numbers to the specified numeric type. This code illustrates:

short shParse  = Int16.Parse("100");

int iParse     = Int32.Parse("100");

long lparse    = Int64.Parse("100");

decimal dParse = decimal.Parse("99.99");

float sParse   = float.Parse("99.99");

double dbParse = double.Parse("99.99");

TRyParse, introduced in .NET 2.0, provides conditional parsing. It returns a boolean value indicating whether the parse is successful, which provides a way to avoid formal exception handling code. The following example uses an Int32 type to demonstrate the two forms of tryParse:

int result;

// parse string and place result in result parameter

bool ok = Int32.TryParse("100", out result); 

bool ok = Int32.TryParse("100", NumberStyles.Integer, null,

                         out result);

In the second form of this method, the first parameter is the text string being parsed, and the second parameter is a NumberStyles enumeration that describes what the input string may contain. The value is returned in the fourth parameter.