Articles » Languages » C# » General

C#Lectures - Lecture 1: Primitive Types

Sergey Kizyan, 1 Mar 2016 CPOL

4.92 (35 votes)

1

2

3

4

5

4.92/5 - 35 votes

3 removed

μ 4.80, σa 1.08 [?]

I'm starting a set of C# lectures for our engineers. The first lecture is about C# built-in types also known as primitive types.

Download source - 5.1 KB

Full Lectures Set

C#Lectures - Lecture 1: Primitive Types

C# Lectures - Lecture 2: Work with text in C#: char, string, StringBuilder, SecureString

C# Lectures - Lecture 3: Designing Types in C#. Basics You Need to Know About Classes

C# Lectures - Lecture 4: OOP basics: Abstraction, Encapsulation, Inheritance, Polymorphism by C# example

C# Lectures - Lecture 5: Events, Delegates, Delegates Chain by C# example

C# Lectures - Lecture 6: Attributes, Custom attributes in C#

C# Lectures - Lecture 7: Reflection by C# example

C# Lectures - Lecture 8: Disaster recovery. Exceptions and error handling by C# example

C# Lectures - Lecture 9:Lambda expressions

C# Lectures - Lecture 10: LINQ introduction, LINQ to 0bjects Part 1

Introduction

This is the first article from the set of C# lectures that I'm doing in my company for our engineers. It is about C# built-in types.

Primitive Types Basics

Every programming language has its own set of basic, built-in data types using which and object oriented approach we can build more complex data types such as classes and structures. C# has its own set of basic, fundamental types. These types are value types which means that when we pass this type as argument to function, they are copied. In this article, I want to show some important and interesting things about value types.

There are 2 sorts of value types:

Built in value types

User defined value types

Basic built-in types in C# are stored under System namespace, they are called primitive types. Because primitive types are used quite often, C# has a simplified way to create them. Instead of writing code like this:

System.Double doubleDigit = new System.Double();

We can use a simpler way:

double doubleDigit = 0;

Actually, we have several ways to define variables of primitive types in C# and it is up to the developer to decide which one to use:

int i =0;
int j = new int();
System.Int32 k = 0;
System.Int32 j = new System.Int32();

Local variables of primitive types must be initialized before they are used.

In both cases, IL compiler will generate the same IL code when you build your project. All C# primitive types have analogs in .NET Framework Class Library. For example, int in C# corresponds to System.Int32 in FCL. The table below shows C# types and their representatives in FCL from MSDN:

Short Name | .NET Class | Type | Width | Range (bits)
byte | Byte | Unsigned integer | 8 | 0 to 255
sbyte | SByte | Signed integer | 8 | -128 to 127
int | Int32 | Signed integer | 32 | -2,147,483,648 to 2,147,483,647
uint | UInt32 | Unsigned integer | 32 | 0 to 4294967295
short | Int16 | Signed integer | 16 | -32,768 to 32,767
ushort | UInt16 | Unsigned integer | 16 | 0 to 65535
long | Int64 | Signed integer | 64 | -9223372036854775808 to 9223372036854775807
ulong | UInt64 | Unsigned integer | 64 | 0 to 18446744073709551615
float | Single | Single-precision floating point type | 32 | -3.402823e38 to 3.402823e38
double | Double | Double-precision floating point type | 64 | -1.79769313486232e308 to 1.79769313486232e308
char | Char | A single Unicode character | 16 | Unicode symbols used in text
bool | Boolean | Logical Boolean type | 8 | True or false
object | Object | Base type of all other types | |
string | String | A sequence of characters | |
decimal | Decimal | Precise fractional or integral type that can represent decimal numbers with 29 significant digits | 128 | ±1.0 × 10e−28 to ±7.9 × 10e28

Short names for us mean that in any of our code files, we have code like this: using byte = System.Byte. This is not actually that but you can assume it is. Some experienced developers as Jeffrey Richter recommend to use FCL types always instead of short names. For example, in C#, long is System.Int64, but other languages may use Int16 and Int32. Also, a lot of methods in FCL types have names that correspond to type names. For example: ReadBoolean, ReadInt32, etc.

All primitive types can be conditionally divided to the following types:

Integral types: sbyte, byte, short, ushort, int, uint, long, ulong

Real float-point types: float, double

Real type with decimal precision: decimal

Boolean type: bool

Character type: char

String type: string

Object type: object

We will concentrate our attention on the first five types and not discuss string and object in this article.

Boolean Type

This is the simplest of the primitive types - it can hold only two values: true or false. You can think about true as 1 and false as 0 if it is more convenient for you. If you convert bool to int, this is what you will get true will be 1 and false will be 0. Bool is the simplest but the most commonly used type in all applications it is used to control the flow of the program and you can see its use in all the conditional operators. Below is the sample code that demonstrates basic operations with bool type:

//declare boolean variable and assign default value for it
//you will see later that default value for bool is false
//so we could avoid assigning it to false and simply define it as bool bVar;
bool bVar = false;
bVar = true;
if (bVar)//here we use boolean value in conditional operator
{
Console.WriteLine("We are here because our boolean value is true");
bVar = false;
}
if (!bVar)
{
Console.WriteLine("We are here because our boolean value is false");
}

Character Type

Char value is 16-bit numerical value. Compiler translates the numeric value to character literal. Unicode characters are used to present most languages of the world plus different specific character sets. Constants of the char can be written as character literals, hexadecimal escape sequence, Unicode representations or can be casted from input integer.

When I tried to assign to char value bigger than maximum, I got a compilation error:

But if this will happen in runtime and compiler can't control it, we will have Overflow exception in checked code and reset value otherwise. We will review overflow later in this article.

Following code at sixth cycle will assign value 0 to char variable:

//when we reach maximum value for char the next one will be 0
int i = char.MaxValue - 5;
for (int j = 0; j < 7; j++)
{
cVar = (char)i;
i++;
}

Integral Types

Variables of integral types contain integers and vary by the size of memory allocated for variable and the signed variable or not. Signed or not defines if variable of integer type can hold negative values. Most commonly used types of integers are int and long. Usually, if you need any integer value, you use int and if size of int doesn't fit your needs, you define long. Int is a 32 bit integer and long is a 64 bit integer. Any literal within int interval is considered as int, integers that are bigger than this are automatically treated as long. Longs that are in int range can be explicitly treated as longs by using "L" or "l" literal at the end:

long lVar = 1L;

In table with types characteristics and below in this article, we get ranges for each primitive type. To decide which one from integral types is needed for you, you may refer to these sections to take a decision.

Real Types

Real types in C# are the real numbers as they are known in mathematics. They are present by floating-point types of different range and precision. Range and precision is crucial to understand in floating-point types. Range defines the minimum and maximum values that type can hold. Precision defines the number of significant figures the variable holds.

float type also known as single precision real number. If you use characters "f" or "F" after digit literal, you explicitly point that the number is of type float. You should know that by default all real numbers are considered as double. Float has precision of seven significant digits. For example, digit 0.123456789 will be rounded to 0.1234568.

double type is known as double precision real number. Suffixes "d" and "D" are used after digit literal to point that number is of type double. The precision of double is form 15 to 16 significant digits . You should know that double has special values Double.PositiveInfinity and Double.NegativeInfinity.

decimal type is known as decimal floating-point arithmetic where numbers are presented in decimal system rather than binary one. This type doesn't lose accuracy when storing and processing floating-pointing numbers. Decimal type has precision from 28 to 29 significant digits . "m" character at the end of digit literal indicates that the number is of type decimal.

Types Characteristics

All primitive types besides string are derived from System.ValueType class which in its turn is derived from System.Object. It means we can call methods of System.Object on any primitive type and all primitive types are derived from System.Object that fits .NET methodology. For example, calling GetType, you may always get FCL type that corresponds to short name. Also, can typeof operator be used for getting type of the variable. Children of ValueType are automatically stored in stack when we declare them. Basing on it, they are very fast and effective.

Following fragment of code shows you some interesting characteristics of few value types in C#:

ushort ushortVar = new ushort();
Console.WriteLine("ushort type" +
" \n\t minimum value: " + ushort.MinValue +
" \n\t maximum value: " + ushort.MaxValue +
" \n\t default value for unassigned variable: " + ushortVar +
" \n\t FCL type: " + ushortVar.GetType() +
" \n\t size in bytes: " + sizeof(ushort));

long longVar = new long();
Console.WriteLine("long type" +
" \n\t minimum value: " + long.MinValue +
" \n\t maximum value: " + long.MaxValue +
" \n\t default value for unassigned variable: " + longVar +
" \n\t FCL type: " + longVar.GetType() +
" \n\t size in bytes: " + sizeof(long));

ulong ulongVar = new ulong();
Console.WriteLine("ulong type" +
" \n\t minimum value: " + ulong.MinValue +
" \n\t maximum value: " + ulong.MaxValue +
" \n\t default value for unassigned variable: " + ulongVar +
" \n\t FCL type: " + ulongVar.GetType() +
" \n\t size in bytes: " + sizeof(ulong));

float floatVar = new float();
Console.WriteLine("float type" +
" \n\t minimum value: " + float.MinValue +
" \n\t maximum value: " + float.MaxValue +
" \n\t default value for unassigned variable: " + floatVar +
" \n\t FCL type: " + floatVar.GetType() +
" \n\t size in bytes: " + sizeof(float));

Here is the result of the program above:

As you can see, we can see using method GetType of System.Object, we can read the FCL type of C# primitive type. Also using sizeof operator, we can read the size in bytes that is allocated for primitive type variable. Also, we get maximum and minimum values for types where it is possible.

(Full version of program, you can see in the attachment.)

Types Casting

There are two kinds of types casting between primitive types:

Implicit type casting - when compiler automatically casts one type to another. This happens when type casting is "safe" and there is no data loss. For example, casting from Int32 to Int64.

Explicit type casting - when developer takes a risk and explicitly sets the type to which we convert the value.

Samples:

short short_value = 10;
int int_value = short_value; //implicit casting
byte byte_value = (byte) short_value; //explicit casting

The rules how C# casts values with "not safe" cases, when the value can be bigger than maximum value of the type to which we cast are described in specification of C# under "Conversions". If you are not sure when doing explicit casting, I recommend you to write short test application with possible input values and try to cast them.

Overflow

When you work with primitive types, especially types that don't have big range for values such as short or byte, you may come to the very sensitive topic called overflow. If for example, byte variable has value equal to 200 and you add to it 60. What will happen? Maximum value for byte is 255, so we don't have place for 260 here. By default, C# doesn't react with exception to such a fact and simply adds 55 to original value and then when it reaches maximum value, we start from 0. In other words, 200 + 60 = 5. Basing on this fact, you should be very careful when working with such a thing as overflow, sometimes you can use it for your purposes and adopt your application for this, but sometimes this may be very efficiently hidden bug that is hard to catch. To avoid the overflow and get system reaction for it, you may use compiler option add.ovf which will generate System.OverflowException when you have it. Also you may use checked instruction for part of code and this code will also generate same exception. As you can see, developer has an option to control the overflow, but you should be familiar with tools that are available for you. See code snippet below that demonstrates the overflow:

byte v = 255;
Console.WriteLine("Insert any positive value:");
int c = Console.Read();
//here we have value of byte that reached more than maximum value, but
//the result is a new we didn't receive overflow exception since by default
//compiler doesn't react to overflow for primitive types and
//not generate System.OverflowException
//to add the check for oveflow you need to add "/checked+" to compiler command line
byteVar = (byte)(v + c);
Console.WriteLine("New byte is: " + byteVar);
//we have also another way to make operation checked
try
{
byteVar = checked((byte)(v + c));
}
catch (OverflowException e)
{
Console.WriteLine("Overflow exception catched: " + e.Message);
}

You can use compiler option /checked+ and then system will control each operation of addition, subtraction, multiplication and type casting for overflow and raise OverflowException when it happens. If you use this option, the program will work slowly, but I recommend you to use this option at least for testing phase.

P.S. I'm missing string type here as my next lecture will be about text processing in C# and string will be described in detail there.

Listing

Full listing of small application that shows primitive types example is available as attachment.

Sources

Jeffrey Richter - CLR via C#

Andrew Troelsen - Pro C# 5.0 and the .NET 4.5 Framework

MSDN

http://www.introprogramming.info/english-intro-csharp-book/read-online/chapter-2-primitive-types-and-variables/

http://www.dreamincode.net/forums/topic/217947-c%23-primitives-built-in-types/

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sergey Kizyan

Architect

Ukraine

Working on different projects and technologies from web to low level core programming, from scripting languages to C++. With all this stuff my personal opinion is that C#,.NET and Microsoft environment is the best thing programmer may have. Basing on it I prefer to publish only about my favorite technologies that are .NET and Azure now.

P.S. Looking for partnership and cooperation in outsourcing.

You may also be interested in...

10 Ways to Boost COBOL Application Development

Generate and add keyword variations using AdWords API

Visual COBOL New Release: Small point. Big deal

Window Tabs (WndTabs) Add-In for DevStudio

SAPrefs - Netscape-like Preferences Dialog

WPF: If Carlsberg did MVVM Frameworks: Part 3 of n

Comments and Discussions

17 messages have been posted for this article Visit http://www.codeproject.com/Articles/1032174/CsharpLectures-Lecture-Primitive-Types to post and view comments on this article, or click here to get a print view with messages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160730.2 | Last Updated 1 Mar 2016

Article Copyright 2015 by Sergey Kizyan
Everything else Copyright © CodeProject, 1999-2016