How to Write Program Logic & Objects with C Sharp (C#)

So you want to get started making programs with C Sharp! How do you do that?

C Sharp (or C#) is a fantastic language that has robust desktop applications for software and game development. In fact, the TIOBE index frequently ranks the language in the top 5 of the most popular programming languages. As such, you can feel comfortable knowing you’re learning an in-demand language. Not only that, but C Sharp can be used for both software or games (this is even the default language for the popular Unity engine), making it an all-around a general-purpose powerhouse.

In this article, we’re going to help you expand your knowledge of C Sharp and teach you some fundamental techniques for creating actual program logic with your program data. We assume you already know common language infrastructure like how to control and manipulate data, but if not, you can check out our post on that topic. We also recommend downloading Visual Studio if you haven’t done so, since Visual Studio is the main IDE used for creating a Net project with C Sharp.

If you’re ready to learn more about C Sharp, let’s dive in!

What is C Sharp?

C Sharp, more commonly written as C#, is one of the world’s most popular programming languages available right now. Developed by Microsoft and based on the C programming language, C Sharp offers developers many features such as object oriented programming paradigms, automatic garbage collection, the ability to connect with LINQ extensions, and so forth. It is an efficient powerhouse that has been used for developing desktop applications, games (particularly games made with Unity), and even a few web applications.

As the language is developed by Microsoft itself, it also integrates well with many of Microsoft’s available web services. These web services allow you to add a variety of new and exciting features – particularly those related to machine learning and AI.

Decision Control in C#

An important part of coding is having your program make decisions. This is what enables your application to seem intelligent, controls the flow of code execution, determines which action to take, determines what to do based on user interaction such as data entered or where they clicked | tapped and so much more!

In C# there are two key Decision Control options:

  • IF Statement
  • SWITCH Statement

Hand writing down flow chart

IF Statement

The IF Statement controls the flow of an application by providing a Boolean ( bool ) condition check and a block of code to run IF the condition returns True.

How to code an IF Statement:

  • Start with the if keyword
  • Follow with a conditional check inside parens (condition-returns-boolean)
  • Open a code block with curly braces {}
  • Inside code block, place the code to run if the condition is True
  • Provide else if blocks, in the same way, to run if True and preceding conditions were False (optional)
  • Provide else block, in the same way, to run if all preceding conditions were False (optional)

Like most programming concepts this is best illustrated with a simple example. Let’s say we have a simple calculator. We perform math calculations based on whether the arithmetic operator is addition ( + ), subtraction ( ), multiplication ( * ) or division ( / ). Let’s run the code four times, changing the mathOperator value each time.

using System;

class MainClass {
  public static void Main (string[] args) 
  {    
    // IF Statement
    string mathOperator = "/";
    int num1 = 20;
    int num2 = 5;
    int calcResult;
    
    if (mathOperator == "+"){
      calcResult = num1 + num2;
    } else if (mathOperator == "-") {
      calcResult = num1 - num2;
    } else if (mathOperator == "*") {
      calcResult = num1 * num2;
    } else if (mathOperator == "/") {
      calcResult = num1 / num2;
    } else {
      calcResult = -1;
    }
    Console.WriteLine(num1 + " " + mathOperator + " " + num2 + " = " + calcResult);
  }
}

In the Console we get the following results:
Result for addition ( + ) is       20 + 5 = 25
Result for subtraction ( - ) is    20 - 5 = 15
Result for multiplication ( * ) is 20 * 5 = 100
Result for division ( / ) is       20 / 5 = 4

The first time a condition returns True, its associated code block runs and the IF Statement is exited without running any additional code inside. If no conditions return True, then the optional else code block runs; if available.

IF Statement – Multiple Conditions

C# can check more than one condition at a time. These multiple condition checks ( AND &&, OR || ) are very useful in IF-based Decision Control.

  • For AND ( && ) both conditions must be True for the result to be True. If the first comparison returns False the second condition is not checked and False is returned. If the first condition returns True then the second condition is checked and its value determines the result.
  • For OR ( || ) either condition can be True for the result to be True. Only if both conditions are False will False be the result.

For example, since we know Divide-By-Zero will throw an error, we can add an additional check if the mathOperator == “/”. Notice that when we set num2 to equal 0 the second part of the / condition fails and therefore the condition returns False and the calculation is not performed. With all previous conditions returning False, the code inside the else block is run, setting the final calculation result.

using System;

class MainClass {
  public static void Main (string[] args) 
  {    
    // IF Statement - Multiple Conditions
    string mathOperator = "/";
    int num1 = 20;
    int num2 = 0;
    int calcResult;
    
    if (mathOperator == "+"){
      calcResult = num1 + num2;
    } else if (mathOperator == "-") {
      calcResult = num1 - num2;
    } else if (mathOperator == "*") {
      calcResult = num1 * num2;
    } else if (mathOperator == "/" && num2 != 0) {
      calcResult = num1 / num2;
    } else {
      calcResult = -1;
    }
    Console.WriteLine(num1 + " " + mathOperator + " " + num2 + " = " + calcResult);
  }
}

In the Console we get the following results:
Result for addition ( + ) is       20 + 0 = 20
Result for subtraction ( - ) is    20 - 0 = 20
Result for multiplication ( * ) is 20 * 0 = 0
Result for division ( / ) is       20 / 0 = -1

The first time a condition returns True, its associated code block runs and the IF Statement is exited without running any additional code inside. If no conditions return True, then the optional else code block runs; if available.

SWITCH Statement

SWITCH Statements are a great way to have very clean code when you have a single variable that could have multiple values and you need to take different actions based on its value.

You may find that a switch is easier than coding many else if statements. While it takes up the same space and provides the same result the switch statement generally makes your code cleaner and easier to understand.

Let’s use the same simple calculator example we used to demonstrate IF Statements and convert the code to use a switch block instead. We can even place an if inside a switch case to cover the Divide-By-Zero issue we mentioned above when discussing IF Statements – Multiple Conditions.

// SWITCH Statement
string mathOperator = "/";
int num1 = 20;
int num2 = 4;
int calcResult = -9999;

switch (mathOperator) {
  case "+":
    calcResult = num1 + num2;
    break;
  case "-":
    calcResult = num1 - num2;
    break;
  case "*":
    calcResult = num1 * num2;
    break;
  case "/":
    calcResult = (num2 != 0) ? num1 / num2 : -1;
    break;
  default:
    Console.WriteLine("Please use one of the following four operators: +, -, *, /");
    break;
}

Console.WriteLine(num1 + " " + mathOperator + " " + num2 + " = " + calcResult);

The first time a condition returns True, its associated code block runs and the switch block is exited by the break; statement without running any additional code inside. If no conditions return True, then the optional default code block runs; if available.

In the Console, we get the following results (notice that we get the same output we get when using an IF Statement):

Result for addition ( + ) is       20 + 5 = 25
Result for subtraction ( - ) is    20 - 5 = 15
Result for multiplication ( * ) is 20 * 5 = 100
Result for division ( / ) is       20 / 5 = 4

Icon with recycling image

Loops in C#

Loops allow us to repeat a block of code as long as a certain condition is met. For example, if we wanted to print the numbers 1 through 10 and didn’t know about loops we might do something like this:

Console.WriteLine("1");
Console.WriteLine("2");
Console.WriteLine("3");
Console.WriteLine("10");

This does not make our code clean or DRY (don’t repeat yourself) so violates coding best practices and will become very tiresome – imagine if you want to print all the numbers between 1 and a 1000 or 10,000 or more!

To solve this in C# we have two primary loops:

  • WHILE Loop
  • FOR Loop

We also discuss a very common combination in programming which is using Loops and Arrays together.

WHILE Loops

The first type of loop we’ll look at is the WHILE Loop. This loop is great when we want to repeat code for as long as a certain condition is met. You will often use this in games by creating a game loop!

This loop syntax is the simplest and looks very similar to an IF-statement; we just use the keyword WHILE instead of IF; then we have the parens (condition) that hold the condition and curly braces {loop-code} that contains the code.

What happens inside the curly braces is very different though. The IF Statement runs a block of code IF the condition is True. The WHILE Loop runs a block of code UNTIL the condition is False.

The syntax of a WHILE Loop is: WHILE (condition-returning-boolean){code to repeat}. For example:

// WHILE LOOP
int i =0;
while (i == 0) {
  i++;
  Console.WriteLine(i);
}

Before the loop runs at all, it checks to see if the condition is true, the loop then continues until the loop condition is false. In this example:

  1. Condition i == 0 is true since it is set in the line above the loop
  2. Code runs and i is incremented by one
  3. Condition i == 0 is now false since i is now 1
  4. Loop exits

IMPORTANT NOTE: we must have a way for the loop to eventually return FALSE; otherwise we create what is known as an INFINITE-LOOP which will cause our app or website to hang and eventually crash! For example, be very careful of setting a condition like this:

// INFINITE WHILE LOOP - BAD
int i = 0;
while (i <= 0) {
  i++;
  Console.WriteLine(i);
}

In this example, the condition never becomes false so it will run forever or until your program crashes!

FOR Loops

FOR Loops are great when you want to repeat an action a set number of times such as printing the numbers 1 to 10 or iterating through all the items in an array. Instead of 10 lines of code to print numbers 1 to 10, we write one print line and run it for 10 iterations.

The FOR Loop keeps track of what iteration we are on; you’ll often see this iteration variable just called i unless there is reason to use a different name. When there are loops within loops you’ll often just see the inside loop variable called j. The name doesn’t matter.

Iteration variables almost always start at 0 (but could be started at a different number if you have a good use-case for doing so). i increases, usually by one on each iteration and we have access to its value inside our loop code.

The syntax of a FOR Loop is: FOR (initialize-loop-variable; condition-to-keep-looping; modify-loop-variable-after-each-iteration){code to repeat}. For example:

Console.WriteLine("How many numbers should we print?");
int count = Convert.ToInt32(Console.ReadLine());
for (int i =1; i<= count; i++) {
  Console.WriteLine(i);
}

This code produces the following Console output when the user enters 11 in response to the question:
How many numbers should we print?
11
1
2
3
4
5
6
7
8
9
10
11

Before the loop runs, we get the count (number of times the loop will run) from the user. In this example:

  1. Start i at one. This code runs only once – just before the loop starts.
  2. On each iteration, check i against the count value the user entered. If i is less than or equal the count then keep looping; if false then the loop ends. This check runs before each iteration.
  3. Run code inside the loop.
  4. After each iteration, increment i, before condition (step 2) is checked again.

Loops and Arrays

The most common use of a loop is with arrays. Using a FOR Loop, you can access and/or modify each element of an array in sequence.

// Arrays and Loops
int[] cards = new int[52];
for (int i=0; i<cards.Length; i++) {
  cards[i] = i+1;
  Console.WriteLine(cards[i]);
}

In this example, we create an empty array with 52 empty places to store data. Since empty places still count towards an array’s length ( cards.Length ) we can use this value in the condition of the FOR Loop. Recall that the Array length property starts with an uppercase L and is a property, not a method so has no parens () following it. We loop through each element setting its value to the current loop variable plus one (since the first Array index is always zero) and write that value to the console.

Nighttime cityscape behind computer screens showing binary

C# Methods

Every C# program has at least one method, called Main that is the entry point for every C# application and is called by .NET’s runtime (known as the common language runtime – CLR) when the program is started. So far we have written all our code inside of Main. To create methods, we must do it outside of Main (it can be above or below just not inside).

The main benefit of Methods is that they allow you to re-use code! Methods, sometimes referred to as Functions, are blocks of code that contain a series of statements that perform a task we can call over and over. They can have as many lines of code as you like but it should be limited to carrying out one particular task. This makes your code more reusable.

Methods allow us to encapsulate related code then execute that code as many times as we need to by calling the Method name. Any code put inside the curly braces {} is considered part of the Method.

using System;

class MainClass {
  public static void Main (string[] args) {
    Greeter();
  }

  static void Greeter() {
    Console.WriteLine("Hello World!!!"); // Hello World!!!
  }
}

Since only the code inside the Main method will be run when the program starts we must have a way for C# to reach our method. In this simple example, we called the method using its name followed by parens (). This is known in C# as Invoking a Method.

Once C# executes the code inside the method it returns to the line that called the method and continues with code execution as usual. For example, in some cases, this line has other work to do such as storing the returned result of the method in a variable or checking its value against another if it was called from within an if statement. If there is no return value then the next line of code below the method call is executed.

We can execute a Method as many times as we like, even though we have only written the code once. We will see this as being more powerful when we look at passing parameters to C# Methods.

Method Signature

Methods have several parts to their signature:

  • Access level (optional) such as public or private (default)
  • Return value data type or void if no value is returned
  • Method name
  • Parameters (optional)
    • enclosed by parens () – empty if no parameters
    • separated by commas , if more than one

Each signature must be unique but the name of the Method need not be. For example, in the Greeter Method below, the only difference is the parameters the method takes. Notice that we can call the method Greeter using either method signature:

using System;

class MainClass {
  public static void Main (string[] args) {
    Greeter();
    Greeter("C#");
  }

  // Greeter Method - NO PARAMETERS
  static void Greeter() {
    Console.WriteLine("Hello World!!!"); // Hello World!!!
  }

  // Greeter Method - WITH PARAMETERS
  static void Greeter(string name) {
    Console.WriteLine("Hello " + name +"!!!"); // Hello C#!!!
  }
}

C# Method Invocation

Methods are called or Invoked, based on whether they are Instance Methods or Static Methods.

Instance methods are part of Object-Oriented programming and are called on an instantiated object (more about this in the Class section). This type of method operates on the instance object and its state data.

In contrast, static methods are invoked using its name and can operate on the data passed to it via parameters but cannot directly access instance object data.

Notice that the Main method has the keyword static before it. We will create all our methods in this section the same way. While static methods may be created within a Class, it is independent of it. This will make more sense when we learn about Classes and Objected-Oriented programming in the next section.

Passing Parameters

Parameters provide power and smarts to our apps. We use parameters by including its data type followed by the name you want to give to the parameter. For example, in the code below our DogYears method accepts two parameters, name and age. You can use as many parameters as you like or none at all.

using System;

class MainClass {
  public static void Main (string[] args) {
    Console.Clear();

    DogYears("Rover", 4);
    DogYears("Spot", 2);
  }

  // MULTIPLE PARAMETERS
  static void DogYears(string name, int age) {
    int dogYears = age * 7;
    string message = "Hello "+name+"!, you are "+age+" in people years but "+dogYears+" in dog years!";

    Console.WriteLine(message);

    // Results:
    // When parameters are "Rover" and 4
    // Hello Rover!, you are 4 in people years but 28 in dog years!

    // When parameters are "Spot" and 2
    // Hello Spot!, you are 2 in people years but 14 in dog years!
  }
}

C# Method Return Statement

In C#, you can return a value from a Method. In the previous Method examples, you may have noticed that the Method Signatures included the void keyword which told C# that we were not returning anything from the Method.

If we do want to return a value we replace void with the data type of the value we want to return to the Method Caller. In this example we are returning a double so we create our Method like so:

using System;

class MainClass {
  public static void Main (string[] args) {
    Console.Clear();

    double resultAdd = AddValues(2, 5);
    Console.WriteLine(resultAdd);       // 7

    Console.WriteLine(AddValues(3,8));  // 11
  }
  // RETURN A RESULT FROM METHOD
  static double AddValues(double num1, double num2) {
    return num1 + num2;
  }
}

Notice you can call the method as many times as you like, passing in different values as parameters. The returned value can then be stored in a variable or used directly.

Let’s create a method to be called from multiple other methods. For this example, let’s check if a number is even or odd by using the C# modulus % operator.

using System;

class MainClass {
  public static void Main (string[] args) {
    Console.Clear();

    Console.WriteLine("---- Parameters - store result in variable");
    double resultAdd = AddValues(2, 5);
    Console.WriteLine(resultAdd); // 7

    Console.WriteLine("---- Parameters - use directly");
    Console.WriteLine(AddValues(3,7)); // 11

    Console.WriteLine("---- Array Parameter - add a list of numbers");

    double[] numbersToAdd1 = {1,3,5,7,9};
    double[] numbersToAdd2 = {1,3,5,7,9,1};

    Console.WriteLine(AddValues(numbersToAdd1));
    Console.WriteLine(AddValues(numbersToAdd2));
  }

  // RETURN A RESULT FROM METHOD
  static double AddValues(double num1, double num2) {
    double result = num1 + num2;
    Console.WriteLine("---- Even or Odd ----");
    // print if result is even or odd
    if (isEven(result)) {
      Console.WriteLine("Result "+result+" is even!");
    } 
    else {
      Console.WriteLine("Result "+result+" is odd!");

    }

    return result;
  }

  static double AddValues(double[] numbersToAdd) {
    
    double result = 0;

    for (int i=0; i < numbersToAdd.Length; i++) {
      result += numbersToAdd[i];
    }

    Console.WriteLine("---- Even or Odd ----");
    // print if result is even or odd
    if (isEven(result)) {
      Console.WriteLine("Result "+result+" is even!");
    } 
    else {
      Console.WriteLine("Result "+result+" is odd!");

    }

    return result;
  }

  // Create a Method to be called from multiple other methods
  static bool isEven(double num) {
    // check if even using modulus operator (%)
    return (num % 2 == 0);
  }
}

This code produces the following Console output:
---- Parameters - store result in variable
---- Even or Odd ----
Result 7 is odd!
7
---- Parameters - use directly
---- Even or Odd ----
Result 10 is even!
10
---- Array Parameter - add a list of numbers
---- Even or Odd ----
Result 25 is odd!
25
---- Even or Odd ----
Result 26 is even!
26

Banner for C Sharp Objects

C# Classes and Objects

A class allows us to bring together a named set of variables and methods to create a blueprint, model or specification that describes the attributes and functionality, in code, of an entity in the world.

Let’s say I want to represent “My Dog” in code. “My Dog is a unique instance of “A Dog. By creating a Dog class we can define a blueprint of the common characteristics and behaviours of a Dog. Then, using the class as a blueprint, we can create an Object Instance that represents “My Dog (the actual entity).

Object-Oriented C#

C# is an Object-Oriented programming language. Object-Oriented Programming (OOP) is a major subject in itself so this will just be a high-level overview of what you need to know to begin using Classes and Objects in C#. There are four pillars of OOP and we’ll touch on them in the following sections. The four pillars are:

  • Encapsulation
  • Abstraction
  • Inheritance
  • Polymorphism

We’ve already discussed ways of representing basic data types such as string for text, int and double for numbers and bool (booleans) to represent all types of true and false values and results. While these data types are foundational, they do not provide a way to model the attributes and interactions of complex entities (objects) in our real or virtual world. In C#, we can do this by defining a custom type using a class.

Class Syntax

Let’s explain class syntax by defining a Dog Class (custom type) and walking through its pieces.

class Dog {
  public string Name;
  public int Age;

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");
  }
}

class Dog defines the class, or type, being created. Everything inside the curly braces {…} that follows the class declaration defines the attributes and actions this class represents. We can say that this simple class (Dog) has three members. Name and Age are properties that manage the data (state) to be stored by the Object Instance created from this class blueprint (for example – myDog). The other class member Bark() is a method. Methods are blocks of related code that should perform a single task and be named in a way that makes that task obvious to you and any other developers who may look at this code in the future (including future-you).

Access Modifier

Access Modifiers define where we can access the property or method of a Class. It can be private (default) or public. When private , the property or method can only be used within the class. When set to public it can be accessed outside the class.

Creating Class Instance Object

While the class is a specification or blueprint, an Instance Object is a representation of our actual dog (based on the blueprint defined by the class). We create this Instance in code outside our actual Dog Class by using the name of the class as if it were a data type, followed by the name we want to give our Object. We then set that equal to a new Object (Class Instance) using the assignment operator = followed by the new keyword and the class name followed by open and closing parens () as if we were calling a Method. Inside the Main Method, located inside the Main Class, its syntax looks as follows:

class MainClass {

  public static void Main (string[] args) {

    Dog myDog = new Dog();

  }
}

myDog is now a representation of an actual dog and we can assign a name, age and call its Bark() method as defined in the class Dog
using System;

class MainClass {

  public static void Main (string[] args) {

    Dog myDog = new Dog();
    myDog.Name = "Fido";
    myDog.Age = 5;

    Console.WriteLine("My dog's name is "+myDog.name);
    
    myDog.Bark();

  }
}

class Dog {
  public string Name;
  public int Age;

  public void Bark() {

    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");

  }
}

When this code is run we get the following result in the Console:
Fido says Woof!!! I am 5 years old.

Class Constructor

The Class Constructor is a special method in C# that defines what to do when the class is created. It’s often used to set variables. To create a constructor, simply add a structure that looks very much like a Method except we do not define a Return type.

The Constructor is very easy to create and looks very much like a simple Method. As with a Method, you can use an access modifier (such as public) so it can be reached from outside the Class itself. As for a name, we must use the same name (including letter casing) as its class name. Finally, just like when creating a Method we can use parameters to allow property information to be passed in when the Class instance is created (referred to as Instantiated).

Let’s demonstrate this functionality by simply writing out a line to the Console when our Dog Class is created.

class Dog {
  public string Name;
  public int Age;

  public Dog() {
    Console.WriteLine("Creating Dog Object!");
  }

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");
  }
}

When this code is run we get the following result in the Console:
Creating Dog Object!
My dog's name is Fido
Fido says Woof!!! I am 5 years old.

In C#, you can actually have multiple Constructors. Let’s say we want to keep our ability to create a Dog Object by passing in no parameters but we would also like the option of assigning the dog’s name and age when we create our Dog instance. We could do this by creating another Constructor for our Class. This time we create a Constructor for our Dog Class passing in two parameters: name and age. We’ll also modify our existing Constructor to take in a name (this means that when a new Dog is created, we must pass in at least a name).
class Dog {
  public string Name;
  public int Age;

  public Dog(string _name) {
    Name = _name;
  }

  public Dog(string _name, int _age) {
    Name = _name;
    Age = _age;
  }

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");
  }
}

Notice that when we define the parameters for the Dog Class Constructor we include the data type and name of each parameter inside the parens (string _name, int _age) separated by commas in the same way we define parameters for any method. These parameter variables are private by default. One interesting convention you may see often in C# is that private properties are prefixed with an underscore ( _ ).

Now from main we can create a second Dog instance and assign its name and age in one line which makes our code much cleaner especially when we create multiple instances (more than one dog in our example).

using System;

class MainClass {

  public static void Main (string[] args) {

    Dog myDog = new Dog("Fido");
    myDog.Age = 5;
    
    Console.WriteLine("My dog's name is "+ myDog.Name);

    myDog.Bark();

    Dog myFriendsDog = new Dog("Buddy", 3);

    Console.WriteLine("My dog's name is "+ myFriendsDog.Name);

    myFriendsDog.Bark();

  }
}

When this code is run we get the following result in the Console:
My dog's name is Fido
Fido says Woof!!! I am 5 years old.
My friend's dog's name is Buddy
Buddy says Woof!!! I am 3 years old.

Class Properties

So far we’ve actually been using public class member variables and not true C# properties. So what’s the difference?

Since C# is an Object-Oriented programming language, a key principle is called Encapsulation. This essentially means that the internal state and functionality of Object (created from a Class blueprint) is hidden from the rest of our application. The only way to access or modify this state is through a public set of functions known as Getters and Setters.

In its simplest form, we really only need to make one small change to each class member variable to convert it to a property. We don’t need to make any changes to the code creating the Objects, setting properties and calling methods.

Change:

class Dog {
  public string Name;
  public int Age;

  // rest of class unchanged
}

To:
class Dog {
  public string Name {get; set;}
  public int Age {get; set;}

  // rest of class unchanged
}

When this code is run we get the same result in the Console:
My dog's name is Fido
Fido says Woof!!! I am 5 years old.
My friend's dog's name is Buddy
Buddy says Woof!!! I am 3 years old.

In this case, C# is automatically setting up a private “backing” field for each of the properties. This field is where the state data is actually stored.

The real power of Getters and Setters is in our ability to make properties read-only and in giving us an easy way to validate incoming data before storing it as state on our Object. To illustrate let’s:

  1. Modify Name to be a read-only property and modify our empty Constructor to take a string name parameter. This change now requires people to enter at least a name when creating a Dog Object.
  2. Add a rule to the Dog’s Age property that ensures the Age is zero or greater. We can modify the Getter and Setter for Age. Note, as soon as we add a body to either the Getter or Setter we must add it to both. This means we must create the private “backing” field ourselves as shown below for the property Age. To test, change age of myDog to be -1. Also, note that the value variable that appears in the Setter is magically supplied by C#.
  3. Add a read-only property DogYears with a Getter but no Setter. This allows code outside our class to use the property’s value but does not allow it to be changed. Now let’s take advantage of the fact that C# properties combine the power of Methods and the Simplicity of Variables to return from the DogYears property a calculated value.

using System;

class MainClass {

  public static void Main (string[] args) {

    Console.Clear();

    // #1 - updated code
    Dog myDog = new Dog("Fido");
    // #2 - deleted code
    // myDog.Name = "Fido"'
    // #2 - modified code
    myDog.Age = -1;
    
    Console.WriteLine("My dog's name is "+myDog.Name);

    myDog.Bark();

    Dog myFriendsDog = new Dog("Buddy", 3);

    Console.WriteLine("My friend's dog's name is "+myFriendsDog.Name);

    myFriendsDog.Bark();

    // #3 - new code
    Console.WriteLine(myFriendsDog.Name + " says Woof!!! I am "+ myFriendsDog.Age + " in human years. That is " + myFriendsDog.DogYears + " in Dog Years!");

  }
}

// --- separate from Main Class (usually in own file)
class Dog {
  public string Name {get;}
  // #2 - updated code
  private int _age;
  public int Age {
    get{
      return _age;
    }
    set {
      if (value >= 0) {
        _age = value;
      } else {
        _age = 0;
        Console.WriteLine("Age must be zero or greater!");
      }
    }
  }
  // #3 - new code
  public int DogYears {
    get {
      return _age * 7;
    }
  }

  // #1 - updated code
  public Dog(string _name) {
    Name = _name;
  }

  public Dog(string _name, int _age) {
    Name = _name;
    Age = _age;
  }

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");
  }
}

Notice that we start the names of private variables with a lowercase letter. While not enforced by C#, this is common practice for private variables. Another common practice is to start private variable names with an underscore ( _ ) followed by a lowercase letter ( _age ). The above code yields the following results in the Console:
Age must be zero or greater!
My dog's name is Fido
Fido says Woof!!! I am 0 years old.
My friend's dog's name is Buddy
Buddy says Woof!!! I am 3 years old.
Buddy says Woof!!! I am 3 in human years. That is 21 in Dog Years!

Class Methods

Methods add functionality to Classes. Note that methods do not end with a semicolon as C# Class properties do. The Bark() method can be called after the Dog Object has been created.

class Dog {
  // existing code not shown
  
  public int DogYears {
    get {
      // updated code
      return ConvertToDogYears();
    }
  }

  // existing code not shown

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " years old.");
  }
}

In this example, the public void Bark() method is available outside this Class ( public ), returns no value ( void ), has the name Bark and takes no parameters ().

Let’s add a second method that calculates dog years. This method private int convertToDogYears() is only available within its Class ( private ), returns an integer value ( int ), has the name convertToDogYears and takes no parameters ().

class Dog {

  // existing code not shown
 
  public int DogYears {
    get {
      // updated code
      return convertToDogYears();
    }
  }

  // existing code not shown

  // new code
  private int convertToDogYears() {
    return Age * 7;
  }
}

Notice that we start the name convertToDogYears() with a lowercase letter. While not enforced by C#, this is common practice for private methods.

Static vs. Instance

The static keyword can be applied to both Properties and Methods. It differs from the default Instance type of Property and Method in that it belongs to the Class itself and not an Object Instance of the Class. In other words, C# keeps a single copy of the variable or method at the Type level (Class), not the Object level.

This really means three important things. static Properties and Methods:

  • Are available to all Object Instances (shared)
  • Cannot access Instance Properties of a Class
  • Cannot call or be called by Instance Methods of a Class

Like most programming concepts this is best illustrated with a simple example. Continuing with the Dog Class we’ve been working with, let’s say we want to:

  1. Keep track of how many dogs our application has created. This type of information does not fit with any particular Object Instance so is a great use-case for static Properties and Methods.
  2. Refactor our convertToDogYears() Instance method to be a static method instead.

Solution:

  1. Add static NumberOfDogs property to our Dog class and increment its value each time a new Dog is created.
    • Since we want this value to be available to be read, but not updated, outside the Dog Class we use public static int NumberOfDogs {get; private set;} = 0; which gives us a public get and a private set.
    • Since the Constructor is called each time a new Dog Instance is created, this is a great location to place to code the increment logic for the static property that will represent our Dog Counter.
  2. Convert our convertToDogYears() Instance method to a static method.
    • Since this method will no longer have access to any Instance Object state, the Age value we use for the calculation will need to be passed in as a parameter.
    • Since the NumberOfDogs property resides at the Type level (Class), not the Object level, we must reference the number of dogs property in the Main Class using the Class name instead of the Object name ( Dog.NumberOfDogs ).

using System;

class Dog {
  public string Name {get;}
  private int _age;
  public int Age {
    get{
      return _age;
    }
    set {
      if (value >= 0) {
        _age = value;
      } else {
        _age = 0;
      }
    }
  }
  public int DogYears {
    get {
      // #2 - updated code
      return convertToDogYears(Age);
    }
  }
  // #1 - new code
  public static int NumberOfDogs {get; private set;} = 0;

  public Dog(string _name) {
    Name = _name;
    // #1 - new code
    NumberOfDogs++;
  }

  public Dog(string _name, int _age) {
    Name = _name;
    Age = _age;
    // #1 - new code
    NumberOfDogs++;
  }

  public void Bark() {
    Console.WriteLine(Name + " says Woof!!! I am "+ Age + " in human years. That is "+ DogYears + " in Dog Years!");
  }

  // #2 - updated code
  static private int convertToDogYears(int _age) {
    return _age * 7;
  }
}

When this code is run we get the following result in the Console:
Fido says Woof!!! I am 5 in human years. That is 35 in Dog Years!
We now have 1 dog running in the park!
Buddy says Woof!!! I am 3 in human years. That is 21 in Dog Years!
We now have 2 dogs running in the park!

Static Classes and Methods

Static classes are essentially the same as regular classes with two key differences:

  • A static class cannot be instantiated. In other words, you cannot use the new keyword to create an Object Instance of the Class.
  • All methods within a static class must be static methods.

Static classes are simply called using the class name itself. This makes a static class great for utility type containers where the methods don’t require an internal state. In other words, these methods take in a value and return a value based on the input or simply perform some type of action when called.

Several examples from C# and the .NET Framework include System.Math, System.Console and System.Convert classes which all contain many convenience methods that can be called directly. Let’s look at a simple example where we create a public static class Calculator with a static method inside. We then use our static class and its static method along with examples from the three C# static classes noted above.

In this example, we use the System.Console class to ask the user to provide a number. We then read that number (which comes in as a string ) and use the System.Convert class to convert it to type double so we can perform math calculations on it. We then take that result and pass it to the custom static double Sqrt method of our custom static class Calculator. We then use the System.Math class to calculate the square root of the passed-in number and return the result. When the Main Method receives our result it uses the System.Console class to write the answer to the Console.

using System;

class MainClass {

  public static void Main (string[] args) {

    Console.Clear();
    Console.Write("Enter number to calculate Square Root: ");
    double num = Convert.ToDouble(Console.ReadLine());
    Console.Write("Answer: ");
    Console.Write(Calculator.Sqrt(num));
  }

  // --- separate from Main Class (usually in own file)
  public static class Calculator {
      public static double Sqrt(double num) {
      return Math.Sqrt(num);
    }
  }
}

Let’s assume the user enters 81 in the console. Our program calculates the result and prints out 9 as the answer.
Enter number to calculate Square Root: 81
Answer: 9

Banner for C Sharp Object-Oriented Topics

C# Inheritance

An important concept in programming is reusability. You may hear this referred to as “keeping your code DRY” which is an acronym for “Don’t Repeat Yourself”. We’ve covered different ways of doing this already in C# such as Methods and Classes. In this section, we discuss another pillar of Object-Oriented Programming which is known as Inheritance.

We’ve talked about Classes as a place to store state (Properties) and functionality (Methods) as encapsulated models of “real world” objects. In this section, we take DRY to another level by abstracting out the state and functionality that are shared between objects (Classes in C#). A classic example is creating two classes to represent a Dog and a Cat. Since they are both animals, a “base” class could be created that holds everything dogs and cats have in common. This helps us reduce redundant code that would have been written (and maintained) in both the Dog and Cat classes. We do this by enabling both the Dog and Cat classes to “inherit” functionality from the Animal class and only add the state and functionality that is unique to them.

using System;

class MainClass {
  public static void Main (string[] args) {

    Animal[] animals = new Animal[] {
      new Animal("Furry", 2, "Animal"),
      new Dog("Rover", 4, "Dog"),
      new Cat("Garfield", 6, "Cat")
    };

    for (var i=0; i < animals.Length; i++) {
      animals[i].Walk();
      animals[i].Run();
      animals[i].Birthday();
      animals[i].Speak();
    }
  }
}

/* --- Animal Class --- (could be in separate file)
Animal is known as the "base" class
*/

public class Animal {
  public string Name {get; private set;}
  public int Age {get;private set;}
  public string BaseText {get; private set;}
  private string type;

  public Animal(string _name, int _age, string _type) {
    Name=_name;
    Age=_age;
    type=_type;
    BaseText = Name+" the "+type;
    Console.WriteLine("Animal, "+BaseText+", has been created!");
  }

  public void Birthday() {
    Age++;
    Console.WriteLine(BaseText+" is now "+Age+" years old! Happy Birthday, "+Name+"!");

  }

  public void Walk() {
    Console.WriteLine(BaseText+" is walking!");
  }

  public void Run() {
    Console.WriteLine(BaseText+" is running!");
  }

  public virtual void Speak() {
    Console.WriteLine(BaseText+" is speaking!");
  }
}

/* --- Dog Class --- (could be in separate file)
Dog is known as a "derived" class and 
inherits from its base class Animal 
using the following syntax:
*/
public class Dog: Animal {

  // Dog Constructor - notice how it calls the base class passing parameters
  public Dog(string _name, int _age, string _type):base(_name, _age, _type) {}

}

/* --- Cat Class --- (could be in separate file)
Cat is known as a "derived" class and 
inherits from its base class Animal 
using the following syntax:
*/
public class Cat: Animal {

  // Cat Constructor - notice how it calls the base class passing parameters
  public Cat(string _name, int _age, string _type):base(_name, _age, _type) {}

}

Notice that the Dog and Cat class constructors call the base class the passing parameters they received when created in the Main method. When this code runs we get the following result in the Console:
Animal, Furry the Animal, has been created!
Animal, Rover the Dog, has been created!
Animal, Garfield the Cat, has been created!
Furry the Animal is walking!
Furry the Animal is running!
Furry the Animal is now 3 years old! Happy Birthday, Furry!
Furry the Animal is speaking!
Rover the Dog is walking!
Rover the Dog is running!
Rover the Dog is now 5 years old! Happy Birthday, Rover!
Rover the Dog is speaking!
Garfield the Cat is walking!
Garfield the Cat is running!
Garfield the Cat is now 7 years old! Happy Birthday, Garfield!
Garfield the Cat is speaking!

C# Polymorphism

In this section, we discuss another pillar of Object-Oriented Programming which is known as Polymorphism. Polymorphism is a Greek word that basically means “many forms”. Like other Object-Oriented concepts, it can be a big topic in itself so we’ll just provide a simple example to illustrate why and how we might use it in C#.

Why? Polymorphism allows derived classes to have different functionality from their base class and their siblings. It provides an elegant opportunity to avoid complex IF or SWITCH Statements, especially when you have many derived classes, to achieve this different behaviour.

How? For the method that you want to be different in your derived class, two changes have to be made. The keyword virtual is added to the base class method and the keyword override is added to the derived class method.

For example, let’s say we want each animal to say something different when the speak() method is called.

using System;

class MainClass {
  public static void Main (string[] args) {

    Animal[] animals = new Animal[] {
      new Animal("Furry", 2, "Animal"),
      new Dog("Rover", 4, "Dog"),
      new Cat("Garfield", 6, "Cat")
    };

    for (var i=0; i < animals.Length; i++) {
      animals[i].Walk();
      animals[i].Run();
      animals[i].Birthday();
      animals[i].Speak();
    }

  }
}

/* --- Animal Class --- (could be in separate file)
Animal is known as the "base" class
*/
public class Animal {
  public string Name {get; private set;}
  public int Age {get;private set;}
  public string BaseText {get; private set;}
  private string type;

  public Animal(string _name, int _age, string _type) {
    Name=_name;
    Age=_age;
    type=_type;
    BaseText = Name+" the "+type;
    Console.WriteLine("Animal, "+BaseText+", has been created!");
  }

  public void Birthday() {
    Age++;
    Console.WriteLine(BaseText+" is now "+Age+" years old! Happy Birthday, "+Name+"!");

  }

  public void Walk() {
    Console.WriteLine(BaseText+" is walking!");
  }

  public void Run() {
    Console.WriteLine(BaseText+" is running!");
  }

  public virtual void Speak() {
    Console.WriteLine(BaseText+" is speaking!");
  }
}

/* --- Dog Class --- (could be in separate file)
Dog is known as a "derived" class and 
inherits from its base class Animal 
using the following syntax:
*/
public class Dog: Animal {

  // Dog Constructor - notice how it calls the base class passing parameters
  public Dog(string _name, int _age, string _type):base(_name, _age, _type) {}

  public override void Speak() {
    Console.WriteLine(BaseText+" says Woof!!!");
  }
}

/* --- Cat Class --- (could be in separate file)
Cat is known as a "derived" class and 
inherits from its base class Animal 
using the following syntax:
*/
public class Cat: Animal {

  // Cat Constructor - notice how it calls the base class passing parameters
  public Cat(string _name, int _age, string _type):base(_name, _age, _type) {}

  public override void Speak() {
    base.Speak();
    Console.WriteLine("Meow!!!");
  }
}

Notice that the Dog and Cat class speak() method implements different functionality than the base Animal class and from each other. Also notice that we can use the base keyword to also call the base class method in addition to our new code. When this code runs we get the following result in the Console:
Animal, Furry the Animal, has been created!
Animal, Rover the Dog, has been created!
Animal, Garfield the Cat, has been created!
Furry the Animal is walking!
Furry the Animal is running!
Furry the Animal is now 3 years old! Happy Birthday, Furry!
Furry the Animal is speaking!
Rover the Dog is walking!
Rover the Dog is running!
Rover the Dog is now 5 years old! Happy Birthday, Rover!
Rover the Dog says Woof!!!
Garfield the Cat is walking!
Garfield the Cat is running!
Garfield the Cat is now 7 years old! Happy Birthday, Garfield!
Garfield the Cat is speaking!
Meow!!!

C# Exception Handling

In applications, sometimes things don’t go as planned. For example, if you’re coding a C# Console Calculator and request the user enter a number, several things could go wrong:

  • The user enters a letter or symbol instead of a number
  • The user tries to divide by zero
  • etc, etc, etc.

In all these cases, C# has been handed data it cannot handle. In these cases, C# throws an exception error and your program crashes.

There are two basic ways to avoid a data error from taking your app down:

  • Proactive – prevent erroneous data from entering your code via “data validation”.
  • Reactive – instead of allowing your app to crash, be prepared to “catch” any exception that is thrown. In so doing you can handle the error any way you choose.

Let’s take the example of a calculator where we get two numbers from the user and multiple them together. What if the user enters a letter when we’re expecting a number.

The “reactive” approach is known as Exception Handling and you implement this by wrapping code that could break your app inside a Try-Catch Block. Basically, you place your code inside the “Try” portion and if the code works…great! If the code fails and an exception error is thrown by C#, the code in the “Catch” portion of the block will be executed instead of simply crashing your program.

using System;

class MainClass {
  public static void Main (string[] args) {
    try {
      Console.Write("Enter a number: ");
      double num1 = Convert.ToDouble(Console.ReadLine());

      Console.Write("Enter a number: ");
      double num2 = Convert.ToDouble(Console.ReadLine());

      Console.WriteLine(num1 / num2);

    } catch(Exception) {
      Console.WriteLine("Does Not Compute... Please Try Again!");
    }
  }
}

Let’s assume the user enters a letter in the console. Since our calculator program excepts numbers and is not designed to “divide” letters, C# throws an exception error. Since we have a Try-Catch block setup, when C# throws the error, our program catches and prints a message to the user.
Enter a number: d
Does Not Compute... Please Try Again!

Ending Words

And we’ve reached the conclusion of this C Sharp guide. Our hope with this guide is that you now better understand how to deal with programming logic when it comes to C Sharp. Whether we’re talking about conditionals, loops, functions, or objects, all of these serve to help guide our data through whatever functionality we’re trying to give our program. This applies whether we’re talking about something as simple as a calculator program, or as complex as a video game. C Sharp has been used for the creation of many amazing things, such as mobile games, multiplayer games, FPS games, animations, and more.

Nevertheless, all these are necessary steps for learning C Sharp. As one fo the most popular programming languages, it has a lot to offer you in terms of developing desktop applications. Though there are other languages out there, such as Python – another one of the most popular programming languages – C Sharp offers many unique benefits.

Of course, there is still more to learn – and the best way to learn a language is by exploring actual projects! So get out there, practice your C Sharp skills, and we can’t wait to see what you create!

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.