C# basics tutorial: Learn variables, classes and lists
We'll walk through the C# language fundamentals. From printing your first line to the console right through to creating and using classes, structs, interfaces, enums and static classes. This is essential if you want to get a job as a C# and .NET developer.
Hello world
To print output to the console in C#, call Console.WriteLine and pass in the text you want to print.
// Program.cs
Console.WriteLine("Hello World");Run the application. This opens a terminal window and prints Hello World.
Variables and types
When declaring a variable in C#, you set the type first, give the variable a name, then set the value. You must define the type of a variable before using it, otherwise the compiler throws an error.
// Program.cs
// Boolean
bool isMale = true;
// String/characters
string myName = "Round The Code";
char lastLetterInName = 'e';
// Numeric
int myAge = 41;
float avgRating = 4.65f;
double cpuUsed = 9.43;
decimal price = 66.55m;A string uses double quotes, while a character uses a single quote with a single character. For decimal places, there are three options: float, double and decimal. The real difference between them is precision. A float needs an f appended to the number, and a decimal needs an m. Leave either of these off and the compiler assumes the number is a double, which throws an error if that is not the type you declared.
float is 32 bit and double is 64 bit, so double can hold a higher maximum value. For money values, decimal is the better choice since it gives higher accuracy, though it does use a bit more space than the others.
Type inference
You do not have to always specify the type. Replace the type with var and the compiler will try to work out the type based on the value.
// Program.cs
// Boolean
var isMale = true;
// String/characters
var myName = "Round The Code";
var lastLetterInName = 'e';
// Numeric
var myAge = 41;
var avgRating = 4.65f;
var cpuUsed = 9.43;
var price = 66.55m;For example, the decimal number with an f appended to it is inferred as a float.
Constants
Variables declared with var are designed to be reassignable, but constants are not. To set a constant, use the const keyword, and you must set the type before declaring the name and the value.
// Program.cs
const int MaxPlayers = 11;
const string TeamName = "Brighton & Hove Albion FC";If you attempt to change the value after it has been declared, you get a compiler error rather than a runtime one, which catches the mistake earlier than a regular variable would.
Math operators
These are the different math operators in C#: + for addition, - for subtraction, * for multiplication, and / for division.
// Program.cs
var totalPrice = 66.55m + 33m;
var discount = totalPrice - 5;
var tax = totalPrice * 0.2m;
var fee = totalPrice / 50;
Console.WriteLine("totalPrice: " + totalPrice);
Console.WriteLine($"discount: {discount}");
Console.WriteLine($"tax: {tax}");
Console.WriteLine($"fee: {fee}");String interpolation
To output a variable alongside other text, you can use the plus symbol and add the variable name, as shown in the first line above. A much better way of doing this is string interpolation. Prepend a $ sign to the string, then wrap the variable name in curly braces, for example $"totalPrice: {totalPrice}".
The braces can hold expressions too, not just variable names, for example $"tax: {totalPrice * 0.2m}".
Casting and conversion
You may want to cast a variable to a different type. Here a double is cast to an int using rounded brackets with the target type.
// Program.cs
double cpuUsed = 9.43;
int rounded = (int)cpuUsed;
Console.WriteLine(rounded);Because the result is an int, the decimal places are removed, so this outputs 9.
You can also convert a variable to a different type. Here, a value of "41" is held as a string because it is wrapped in quotes, and int.Parse converts it to an integer.
// Program.cs
var ageText = "41";
var age = int.Parse(ageText);
Console.WriteLine(age);When doing this, make sure the string is in the right format. If it is not, int.Parse throws an exception.
// Program.cs
var yearOfBirth = "Not sure";
var year = int.Parse(yearOfBirth);Running this throws:
System.FormatException: 'The input string 'Not sure' was not in a correct format.' int.TryParse is the safer option here, since it returns true or false instead of throwing.
Installing Visual Studio
To use C#, you can use Visual Studio.
Install Visual Studio. The Community edition is free, while the Professional edition is for companies that need to pay for the software.
Create a new C# console application.
Run the app using the play button and you should see
Hello worldprinted to the console.
Conditionals
This is how you write an if else statement in C#.
// Program.cs
var myAge = 41;
if (myAge == 40)
{
Console.WriteLine("You are 40 years old");
}
else {
Console.WriteLine("You are not 40 years old");
}If you have multiple lines in the block, you must use curly braces, but they are optional if you only have one line.
You also have else if for multiple conditions.
// Program.cs
var myAge = 41;
if (myAge < 40)
{
Console.WriteLine("You are under 40 years old");
}
else if (myAge == 40)
{
Console.WriteLine("You are 40 years old");
}
else
{
Console.WriteLine("You are over 40 years old");
}A cleaner way of handling multiple conditions is a switch statement. Put the variable in as the switch value, then add each case with its condition, and a default for the else case.
// Program.cs
var myAge = 41;
switch (myAge)
{
case < 40:
Console.WriteLine("You are under 40 years old");
break;
case 40:
Console.WriteLine("You are 40 years old");
break;
default:
Console.WriteLine("You are over 40 years old");
break;
}You can simplify this further using a switch expression.
// Program.cs
var myAge = 41;
var message = myAge switch
{
< 40 => "You are under 40 years old",
40 => "You are 40 years old",
_ => "You are over 40 years old"
};
Console.WriteLine(message);Boolean and logical operators
To group two or more conditions together into a single if statement, use && for AndAlso, or || for OrElse.
// Program.cs
var myAge = 41;
var isMale = true;
if (myAge > 40 && isMale)
{
Console.WriteLine("Over 40 male");
}
if (myAge == 40 || isMale)
{
Console.WriteLine("Is 40, or a male");
}
if (myAge != 40 && !isMale)
{
Console.WriteLine("Not 40, or a male");
}The exclamation mark represents "not", so the final condition reads as not 40 and not male. Combining conditions like this saves you from nesting separate if statements for each one.
Ternary operator
You can write an if else statement in one line using the ternary conditional operator. Put your condition, followed by a ? and the true statement, then a : and the false statement.
// Program.cs
var myAge = 41;
var message = myAge >= 40 ? "You are 40 or over" : "You are under 40";
Console.WriteLine(message);You can chain multiple ternary operators together in one statement, but it is worth avoiding where possible, since too many in one line quickly becomes confusing to read.
Arrays
There are a number of ways to declare an array. You can declare it with the values already set.
// Program.cs
var ages = new int[] { 5, 10, 15, 20 };Or you can declare an empty array with an initial size, then set the values afterwards. The index starts at 0.
// Program.cs
var moreAges = new int[5];
moreAges[0] = 33;
moreAges[1] = 44;Arrays are difficult to resize, and if you go outside the bounds, you get an exception. Setting an index of 10 against an array with a size of 5 throws:
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'Wrap risky code in a try catch block so the exception does not crash the whole program.
// Program.cs
try
{
moreAges[10] = 99;
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"Something went wrong: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"General exception: {ex.Message}");
}The catch block only runs if that specific exception type is thrown, so a general Exception catch is added afterwards to handle anything else.
Multidimensional arrays
There is also support for multidimensional arrays, where you have two or more index numbers. You can declare it as an empty array with the sizes, then set the values, or declare the values as you declare the array.
// Program.cs
var multi = new int[2,2];
multi[0,0] = 192;
multi[0,1] = 192;
var moreMulti = new int[2, 2] { { 192, 192 }, { 146, 149 } }; Lists
Arrays are difficult to resize, which is where lists come in. You have to give a list a type, then you can add entries by calling Add.
// Program.cs
var worldClassPlayers = new List();
worldClassPlayers.Add("Kane");
worldClassPlayers.Add("Messi");
worldClassPlayers.Add("Mbappé");
worldClassPlayers.Add("Yamal");
worldClassPlayers.Add("Ronaldo");
worldClassPlayers.Remove("Ronaldo");
Console.WriteLine(worldClassPlayers.Count);There is a simpler way of doing this too, by setting the values when you declare the list.
// Program.cs
var worldClassPlayers = new List()
{
"Kane",
"Messi",
"Mbappé",
"Yamal",
"Ronaldo"
};If you wish to remove an entry from the list, call Remove, and you can get a count of all the entries by calling Count.
Loops
For loop
// Program.cs
for (var a = 1; a <= 9; a++)
{
if (a % 2 == 1)
{
continue;
}
if (a % 5 == 0)
{
break;
}
Console.WriteLine($"{a} is an even number");
}The variable a starts at 1 and increments by 1 each time, looping up to and including 9. If the number is odd, continue skips straight to the next iteration. If the condition for break becomes true, the loop stops entirely and nothing else inside it runs.
Foreach loop
If you have a list or an array, you can use foreach to loop through it.
// Program.cs
var worldClassPlayers = new[] { "Kane", "Messi", "Mbappé", "Yamal" };
foreach (var player in worldClassPlayers)
{
Console.WriteLine(player);
}You can also use break and continue inside a foreach loop.
While loops
// Program.cs
var x = 0;
while (x < 10)
{
Console.WriteLine($"x is {x}");
x++;
}++ increments a value by 1, and -- does the opposite. Be careful with while loops. If you forget to increment the value, you end up in an infinite loop that never ends.
Do-while loop
// Program.cs
var y = 0;
do
{
Console.WriteLine($"y is {y}");
y++;
}
while (y < 10);The only difference from a while loop is that a do while loop is guaranteed to run at least once, since the condition is only checked at the end.
Classes
When declaring a class, it is advisable to set the namespace so you can group similar objects together. Inside a class, you can set properties, which let you hold values within the class.
// Person.cs
namespace RoundTheCode.CSharpBasics;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person()
{
}
public Person(string name, int age)
{
Name = name;
Age = age;
}
public string Greet()
{
return $"Hi, I'm {Name}";
}
}Constructors can be overloaded. If you are not passing in any parameters, you do not need one at all, but if you want to pass parameters in when initialising the class, you can overload the constructor to accept them, as shown above.
To initialise the class, import the namespace you gave it, then use curly braces to set the properties.
using RoundTheCode.CSharpBasics;
// Program.cs
var person = new Person { Name = "David", Age = 41 };
Console.WriteLine(person.Greet());
var person2 = new Person("David", 41);Properties store the data, and methods let you act on that data. Calling person.Greet() above outputs Hi, I'm David to the console.
Access modifiers
So far, everything has been marked as public, meaning it can be used anywhere in the code. But you can restrict that. A private member can only be used within its own class, and this is also the default if you write nothing at all. There is also internal, which can be used anywhere in the same assembly, and protected, which can be used within an inherited class.
// Employee.cs
public class Employee
{
private int _id;
public string Name { get; set; }
}In the example above, _id cannot be accessed from outside the Employee class, but Name can.
Nullability
Some of your properties might be null. Append a question mark to the type when declaring it to allow that.
// Person.cs
public string? Nickname { get; set; }Without the question mark, the compiler warns you if you try to assign or return null for that property. You can check whether a property is not null before using it.
// Program.cs
if (person.Nickname is not null)
{
Console.WriteLine(person.Nickname);
}You can also use the null conditional operator to safely output a value that might be null, for example person.Nickname?.ToUpper(). Without it, calling a method on a null value throws an exception.
Structs
// Point.cs
public struct Point
{
public int X;
public int Y;
}Structs are very similar to classes. The main difference is that a struct is a value type, whereas a class is a reference type. When you assign these values around, a struct gets copied, whereas a class gets shared. Use structs for small data like coordinates, where copying is cheap and expected.
Interfaces
An interface declares a contract. It sets the methods or properties that a class must implement, without adding the implementation itself.
// IRemoteControl.cs
public interface IRemoteControl
{
void TurnOn();
}// RemoteControl.cs
public abstract class RemoteControl : IRemoteControl
{
protected bool IsOn { get; set; }
public abstract void TurnOn();
}RemoteControl implements the IRemoteControl interface. But it's marked as abstract, meaning you cannot initialise it directly. It implements TurnOn from IRemoteControl but that is also marked as abstract, meaning any class that inherits from it must implement that method.
// SamsungRemoteControl.cs
public class SamsungRemoteControl : RemoteControl
{
public override void TurnOn()
{
IsOn = true;
}
}SamsungRemoteControl implements TurnOn, overriding the abstract method, and sets IsOn to true. Since IsOn is marked as protected on RemoteControl, it can be set from a class that inherits from it, but it could not be set from outside that inheritance chain.
Enums
Enums give you a set of named constant values, which is a much clearer way of working than just setting numbers directly.
// Level.cs
public enum Level
{
Beginner = 1,
Intermediate,
Advanced
}By default, an enum starts at index 0, but you can override that, as shown above, where Beginner is set to 1. To use it in your code, reference the enum followed by the constant you want.
// Program.cs
var myLevel = Level.Intermediate;Static classes
The members inside a static class belong to the class itself rather than an instance, and you cannot create an instance of a static class.
// MathHelper.cs
public static class MathHelper
{
public static int Square(int number) => number * number;
}Call the method directly against the class type, without creating an instance.
// Program.cs
Console.WriteLine(MathHelper.Square(5));Static classes are good for methods that are reused throughout an application.
Watch the video
Watch the video where we walk through variables, conditionals, arrays, lists, loops, classes, structs, interfaces, enums and static classes.
Related tutorials
Learn how to override ToString(), overload operators and use indexers in C# classes, featuring examples of addition and subtraction.
C# 13 has been launched as part of the .NET 9 release and we'll take a look at the new features and how you can start using them today.