In part 4 of my learning C# tutorial series we’re going to talk about variables and types in C#. I hope to give you a general idea of how variables work in C#, and introduce you to types which are a core part of the language. If you’ve done some programming in other languages this will probably be a quick skim, but if you’re a beginner it’s one you won’t want to miss.
What is a variable?
A variable is a storage place for data. Think of it like a mailbox. You have a wall of mailboxes in an apartment building the mail carrier puts mail into the box for later retrieval by you.
C# Tutorials: How to Learn C#
- C# Introduction
- C# Namespaces
- C# Coding Basics
- C# Variables and Types
- C# Selection Statements
- C# Iteration Statements
But how do does he or she know the mail will go to the right people? Each box is given a unique identifier such as an apartment number and possibly your name on the box so each letter that’s addressed to you, will reach you. When you go to retrieve it, you know which box is yours because of those same labels.
That’s how variables work as well. Variables are given unique names so you can identify them later, when storing or retrieving information. You can then store, reuse and manipulate data in program. Each of those variables has a unique name, and a type assigned to it.
1 2 3
What is a type?
Every variable and expression (we’ll get to those) in C# has a type. This is the type of data that’s stored in the variable which could be numbers, letters, or objects. There are several built in types that are mostly for numbers, and there are complex types that you will create such as objects, collections, and more. To find a good analogy for types, look in your kitchen. In one cupboard you have plates, in another bowls, and a drawer for silverware. The cupboards are variables and bowl is a type.
Your kitchen is a loosely typed scenario, because you can put cups with the plates, and move the silverware with the bowls if you really want to. If you’re like me you have a significant other that won’t tolerate such disorganization and will insist everything is kept separate, or “strongly typed”. Bowls go with bowls, and silverware goes in a drawer.
She has a good point: if everything were mixed up we would never be able to find anything when we need it. When I put the dishes away it would be a lot easier and faster to stuff them wherever they fit, but would cause some problems down the road. Programming languages are the same way. I’ll elaborate on that in a bit.
Here are the built in types for C# that we’ll be talking about:
|C# Type||.NET Framework Type||Description|
|bool||System.Boolean||Stores Boolean values true and false|
|byte||System.Byte||Unsigned Integer from 0 to 255|
|sbyte||System.SByte||Signed 8-bit integer from -128 to 127|
|char||System.Char||Unicode 16-bit Character from U+0000 to U+ffff|
|decimal||System.Decimal||128-bit ±1.0 x 10-28 to ±7.9 x 1028 (approximate)|
|double||System.Double||64-bit floating point from ±5.0 x 10-324 to ±1.7 x 10308 (approximate)|
|float||System.Single||32-bit floating point from ±1.5 x 10-45 to ±3.4 x 1038(approximate)|
|int||System.Int32||Signed 32-bit integer from -2,147,483,648 to 2,147,483,647|
|uint||System.UInt32||Unsigned 32-bit integer from 0 to 4,294,967,295|
|long||System.Int64||Signed 64-bit integer from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807|
|ulong||System.UInt64||Unsigned 64-bit integer from 0 to 18,446,744,073,709,551,615|
|object||System.Object||Alias for a .NET Framework object|
|short||System.Int16||Signed 16-bit integer from -32,768 to 32,767|
|ushort||System.UInt16||Unsigned 16-bit integer from 0 to 65,535|
|string||System.String||zero or more Unicode characters|
This is taken from the MSDN Page on Built-In Types which contains more detailed information about each type.
Variables in C#
We call these containers variables because the data frequently changes, yet the type of data it contains doesn’t. Variable can mean several things in C# meaning it can be a local variable, or fields or properties in objects. For now we’ll just talk about local variables that will be used to store information within a method.
To declare a variable, you must first declare the type, then the name you want for it.
This declares an integer value named apples, and sets it to 0. You can just create the variable without any data like this:
But you must assign this variable a value before trying to use it, if you don’t the compiler will give you an error. Let’s take our hello world app, and add this variable to it:
1 2 3 4 5 6 7 8 9 10 11
When you try to compile the program, you get the following warning:
int.cs(7,15): warning CS0168: The variable ‘apples’ is declared but never used
Note that this is only a warning, the program will still compile and run, but you’re warned that you have a variable that isn’t being used. So what happens when we try to use it?
1 2 3 4 5 6 7 8 9 10 11
As you can see we create the variable apples and then we try to use it though it has no value. When you compile it you’ll get the following error:
int.cs(8,57): error CS0165: Use of unassigned local variable ‘apples’
An error is more serious than a warning: this program will not compile. When a local variable is created you have to give it a value before we use it. Change the program to the following:
1 2 3 4 5 6 7 8 9 10 11
Now when you compile it, you’ll get no errors or warnings because you created a variable, assigned it a value of 42, and then used it. After it compiles, run it and you’ll see:
We have 42 apples in our basket
This is our expected output.
A note about variable naming
Notice how we named the variable apples to represent how many apples we have. The truth is, the compiler doesn’t care if you name it apples, oranges, or oiueoriue. It’s only useful for programmers, you could name the variable “a” and the next one you need “b” if you really wanted to. But the next time you go back into your code, or someone else does things will be a lot harder. Always give your variables valuable names that represent the data being stored.
Strings are what we were dealing with in our hello world app. A string is a sequence of Unicode characters that represent text. Most human readable items are stored in strings. A string is a reference type, but you and also use it as an object to do do comparisons and I’ll demonstrate that in a future tutorial. You can learn more about strings in the MSDN C# Reference.
The char type contains a single Unicode character within the valid range. They are 16 bit values and can be very useful in many situations. You can write Hexadecimal Unicode and Integers into a char value when needed.
The Boolean data type only stores either true or false values. You’ll be using Booleans a lot in your expressions. Boolean values are used for checking, validation and flow control. It’s a crucial part of any application. Here’s an example:
Integers represent whole numbers. Integer data types are best for discrete values, such as incrementers, rows in a database or any value constrained to a whole number. The benefit of using integers is the computation is exact, no rounding or guessing involved.
data types that use integers are often referred to as integral data types. This can sometimes confuse new programmers because they trip up on the word “integral” or mistake it for “integrated”. Integral just means a value that uses integers.
Signed and unsigned integers
Of the integer data types you’ll notice some of them have negative numbers some do not. Unsigned integers can only recognize positive numbers, while signed values can represent negative or positive. Why do we have these two different data types? You’ll notice unsigned integers have a much higher maximum value, because it utilizes space that would otherwise be used for negative values.
For example a signed 16-bit integer has a maximum value of 32,767. If the value you’re storing is larger than that you’ll have to use a 32-bit integer. However if you know you’ll never need negative numbers you can use an unsigned 16-bit integer as large as 65,535 in the same 16 bits of space.
Many languages do not support unsigned integers so you’ll sometimes find types in the .NET framework that don’t use negative values, yet still use signed integers for compatibility. The effect this has on memory and performance is very minimal.
8-bit, 16-bit, 32-bit, and 64-bit integers
At the present time 32-bit integers are the most widely used. This is because it offers a very good range of values and is very efficient with 32-bit CPUs. Here are some of the uses for each type:
8-bit - sometimes used for I/0 and network connections when byte-oriented operations are optimal.
16-bit - Mostly used for compatibility with old protocols an interfaces.
32-bit - Most frequently used for integer operations
64-bit - used for very large values where the 32-bit limitations are not optimal.
In version 4 of the .NET framework you have BigInteger as an option. This is for very large values but there is a key difference in that it is a dynamic data type, and it will only use as much space as it needs. As the size of the integer grows more space is allocated, meaning your theoretical size limit is dependent on how much memory you have. Not something you’d want to use unless you absolutely need it.
Floating point numbers are named such because there is a fixed number of digits available, but the decimal point is allowed to “float” around, for example:
While the decimal point is allowed to move within the number the amount of precision changes. Precision is the amount of detail allowed in your value. For example, our monetary system uses a precision of 2 digits, such as
There is no such value as $10.345 because we generally don’t deal in terms of fractions of a cent. As you can see from our table above, you can have float values ranging from ±1.5 x 10-45 to ±3.4 x 1038(approximate). If you need a greater range you can use something like long (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) or even ulong for very large positive values (0 to 18,446,744,073,709,551,615).
Since I mentioned precision earlier, you might be wondering if data can be lost, or calculations can possibly be inaccurate if there is not enough precision and the value is truncated. This is correct, and though it’s fairly accurate if you’re doing something that requires absolute results from computations you’ll want to use the next data type.
For high precision computation such as accounting, you’ll want to use the decimal format. Because floating point numbers are rounded off, you can end up with small incremental changes to each value that can lead to inaccuracies. This is why you would use the aptly named decimal data type for decimal values. Decimal data types have a precision up to 28 digits and won’t give unexpected results for precise calculations.
You want to use this data type only when it’s needed because there is a trade off and decimals are slightly less efficient than double or float because of the conversions from decimal to binary and vice-versa.
In this tutorial I have explained variables, what they are how to assign them. We also talked about some of the types available. Because this started to get so long winded I haven’t covered everything on the subject but given you a good foundation to start with. You’ll be working with variables and types a lot in the future, and I’ll cover more as we go on.
If you have any questions or comments, leave them below I’ll be checking them frequently. In the next tutorial we’re going to cover some statements.