0% found this document useful (0 votes)
20 views126 pages

CSharp Fundamentals. Quick Reference Essentials and Examples

Uploaded by

maxyhunt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views126 pages

CSharp Fundamentals. Quick Reference Essentials and Examples

Uploaded by

maxyhunt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 126

C# Fundamentals: Quick Reference Essentials

and Examples

Perfect for new developers wanting to learn C#

Adam Seebeck

United States
C# Fundamentals: Quick Reference Essentials and Examples

Author: Adam Seebeck

Copy Editor: Samantha Seebeck

© 2018 unQbd

ALL RIGHTS RESERVED. No part of this book may be reproduced or distributed in any form or by any
means except as permitted by U.S. copyright law, without the prior written permission of the copyright
owner.

The information contained within this book is sold without warranty, either express or implied. The
authors, unQbd, dealers, and distributors will not be held liable for any damages caused or alleged to
have been caused by the contents of this book directly or indirectly.

Trademark information for all companies and products mentioned are notated by the appropriate use of
capitals. There is no guarantee from unQbd in the accuracy of this information.

For permission to use material from this text or product, please contact www.unQbd.com/Support or
email [email protected]

ISBN: 978-0-692-19899-5
Production Version: 1.01

unQbd
100 S. Belcher #5483
Clearwater, FL 33765
USA

Printed in the United States of America


Print year: 2018

Unless otherwise noted all items © unQbd.

unQbd (pronounced “un-cubed”) is an education technology company, providing both digital and print
material. Purchase our products at your local college store or at our online store www.unQbd.com.
TABLE OF CONTENTS

C# Fundamentals: Quick Reference Essentials and Examples

ABOUT THIS BOOK ........................................................................................................................... 1


INTRODUCTION TO C# ..................................................................................................................... 2
VISUAL STUDIO: INSTALLING ........................................................................................................... 4
VISUAL STUDIO: CONSOLE APPLICATION SETUP ............................................................................. 5
CONSOLE APPLICATION: “HELLO WORLD!” ..................................................................................... 6
COMMENTS...................................................................................................................................... 7
SNIPPET & SHORTCUT KEYS ............................................................................................................. 8
VARIABLES AND DATA TYPES ........................................................................................................... 9
NAMING CONVENTIONS ................................................................................................................ 12
OPERATORS .................................................................................................................................... 13
INPUT & OUTPUT ........................................................................................................................... 14
CASTING ......................................................................................................................................... 17
IF, ELSE IF, AND ELSE STATEMENTS ............................................................................................... 18
SWITCH .......................................................................................................................................... 22
PARSE & TRYPARSE ........................................................................................................................ 24
LOOPS............................................................................................................................................. 26
ARRAYS ........................................................................................................................................... 29
ARRAYS: 2-D AND 3-D .................................................................................................................... 31
ARRAYS: JAGGED ............................................................................................................................ 33
METHODS ....................................................................................................................................... 34
METHODS: OVERLOAD ................................................................................................................... 38
METHODS: RECURSION .................................................................................................................. 39
METHODS: NAMED ARGUMENTS .................................................................................................. 42
CLASSES .......................................................................................................................................... 43
CLASSES: CONSTRUCTOR ............................................................................................................... 46
CLASSES: STATIC ............................................................................................................................. 47
GET-SET PROPERTIES ..................................................................................................................... 48
CLASSES: INHERITANCE .................................................................................................................. 53
METHOD: VIRTUAL......................................................................................................................... 55
CLASSES: ABSTRACT ....................................................................................................................... 56
CLASSES: PARTIAL .......................................................................................................................... 57
ACCESS MODIFIER: PUBLIC, PROTECTED, AND PRIVATE............................................................... 58
MEMORY: HEAP AND STACK .......................................................................................................... 59
MEMORY: BOXING VS UNBOXING ................................................................................................. 61
STRUCTS ......................................................................................................................................... 62
NAMESPACES & USING DIRECTIVE ................................................................................................ 64
GENERICS ....................................................................................................................................... 66
LIST ................................................................................................................................................. 68
LINKEDLIST ..................................................................................................................................... 71
DICTIONARY ................................................................................................................................... 72
ENUMERATION .............................................................................................................................. 75
TERNARY OPERATOR...................................................................................................................... 77
RANDOM NUMBER ........................................................................................................................ 79
THIS (REFERENCE) .......................................................................................................................... 80
METHODS: EXTENSION .................................................................................................................. 81
TUPLES ........................................................................................................................................... 83
STRINGBUILDER ............................................................................................................................. 84
TRY-CATCH ..................................................................................................................................... 86
UNIT TESTING................................................................................................................................. 88
UNIT TESTING: FACT & THEORY ..................................................................................................... 92
DIRECTIVES ..................................................................................................................................... 93
WRITING/READING TEXT FILES ...................................................................................................... 94
INTERFACES .................................................................................................................................... 95
YIELD .............................................................................................................................................. 97
DELEGATES ..................................................................................................................................... 98
EVENTS ......................................................................................................................................... 100
LAMBDAS ..................................................................................................................................... 103
THREADS ...................................................................................................................................... 105
ASYNCHRONOUS .......................................................................................................................... 108
QUERY EXPRESSIONS: LINQ – QUERY SYNTAX ............................................................................. 111
QUERY EXPRESSIONS: LINQ – METHOD CALL SYNTAX ................................................................ 116
DATABASE .................................................................................................................................... 117
Page |1

ABOUT THIS BOOK

C# Fundamentals: Quick Reference Essentials and Examples explains fundamental software


development concepts and provides easy to follow examples. The structure of the book is in a logical
sequence and is readable from beginning to end. Examples in this book use the following three
techniques:

• Quick Reference Essentials give a brief explanation and include examples of code.
• Full Examples often follow Quick Reference Essentials and expand on the concept by displaying
complete real-world examples of usage.
• Walkthroughs provide step by step instructions on how to complete a specific task.

Quick Reference Essential Examples Full Examples Walkthrough

This book focuses on software development using the C# language and computer software
called Visual Studio (free to download). Both the language and software are covered within this book;
no prior software development knowledge is required. Flowcharts, screenshots, and additional visual
aids are used throughout the book to help explain concepts.
Page |2

INTRODUCTION TO C#

C# (pronounced “C Sharp”) is a modern, easy to use, object-oriented programming language


developed by the Microsoft Corporation. The first version of C# was released in 2002 and the latest
version (7.3) was released in May 2018. C# is the most popular language used within Microsoft’s Visual
Studio platform. Visual Studio is the software used for developing applications; this type of software is
referred to as an Integrated Development Environment (IDE).

C# uses the .NET Platform that contains all the components needed to run an application; one
component is the Common Language Runtime (CLR). The CLR handles various tasks such as compiling
code to 1s and 0s (binary) for the computer to understand. The .NET Standard Library is also within the
.NET Platform and contains shared libraries of code that developers use when developing applications.
This helps developers so they do not have to write code from scratch. For example, if an application
needs to read information from a text file, there is already a built-in class for this and there is no need to
recreate it.

An additional benefit to using C# is its versatility. C# is general purpose language, meaning it can
be used to create many kinds of applications. Built on top of the .NET Standard Library are collections of
app models. These are libraries designed for a specific type of application such as computer software,
websites, or phone apps. The three major app models are: .NET framework, .NET Core, and Xamarin.
Page |3

Listed below are a few examples of apps that can be created using the C# language.

• Console Applications: A console application is a text-based application that contains no


graphical components, such as buttons or images. This book focuses on text-based applications,
because they are easy to demonstrate C# examples.

• Websites: Dynamic websites can be built using C# and ASP.NET in Visual Studio.
• Mobile Applications: Quickly create iOS, Android, and Universal Windows Platform (UWP)
applications using C# and Xamarin in Visual Studio.
• Games: Unity3d is a separate (free) software program used to design 2D, 3D, virtual, and mixed
reality games. While the Unity Game Engine is used to design the game, the coding is still
developed in Visual Studio with C#.
• Computer Software: Software for Windows can be created using WPF, Windows Forms, or
Universal Windows Platform.
Page |4

VISUAL STUDIO: INSTALLING

Visual Studio can be downloaded from “www.VisualStudio.com/downloads”. Download the


Community edition; it is free.

After downloading and beginning the installation process the screen below will be displayed.
This screen contains the components that can be installed. Components can always be added later by
going to top menu bar and selecting “Tools -> Get Tools and Features”.

For this book, make sure to have at least “.NET desktop development” and “.NET Core cross-
platform development” checked. Review all the additional components available to install to become
familiar with the options. Click the install or modify button to continue the installation process.
Page |5

VISUAL STUDIO: CONSOLE APPLICATION SETUP

The following are instructions on how to create a Console Application. Console Applications are
great for demonstrating concepts; they are simple text-based applications.

Walkthrough: Microsoft Windows setup for a Console Application **may vary for Mac computers

1. Open Visual Studio from your Desktop or Start Menu.

Visual Studio Desktop Icon or Start Menu

2. Once loaded, there will be a lot of content on the screen that can seem overwhelming. Ignore all
of that for now.
3. Click File -> New -> Project.

4. On the left menu, select the dropdown for Visual C# and click on .NET Core.
5. On the right menu, select Console App (.NET Core).
6. Toward the bottom of the window, you will see “Name:”, this is where you enter a name for
your program.
7. Click the “Browse” button next to “Location”; this changes the location of where the project is
saved.
8. Clicking “OK” in the bottom right corner will create the Console Application.
Page |6

CONSOLE APPLICATION: “HELLO WORLD!”

When learning a new programming language, it is a tradition to display the words “Hello
World!” on the screen. Please note, this is the only example in the book where an explanation is not
provided about the coding and simply the instructions are given to produce the results.

Walkthrough: Hello World

1. Create a Console application named HelloWorld. The steps to create a Console application can
be found in the previous section “Visual Studio: Console Application Setup”.

2. A page full of unfamiliar code should appear and look like the image below.

By default, Console applications display


“Hello World!”

3. Add the line of code “Console.ReadLine();” below “Console.WriteLine("Hello World!");”.


This line of code will prevent the Console app from closing right after it displays “Hello World!”.

Play Button

Extra line of code needed to stop the


Console application from closing

4. Press the play button or the F5 key to run the Console application.

Congratulations on completing a C# program!


Page |7

COMMENTS

Program comments are essentially notes left on programs to explain or highlight the
functionality of code. Comments are non-executing code and will not affect the usage of a program.

Comment Types:

• Line comments are for a single line of code and begin with two forward slashes “//”. Anything
following the slashes on that line of code will be considered a comment and not execute.
• Block comments are for multiple lines of code and begin with one forward slash and an asterisk
“/*” and to complete the comment end with an asterisk and a forward slash “*/”.

Example: Line comment

// Anything after two forward slashes on this line will not execute.
Console.Write("Hello World!"); // A comment can also be placed after code.

Example: Block comment

/* Comment out multiple lines of code.


Anything in this area is also a comment.
*/

Visual Studio has a convenient way to quickly comment or uncomment selected lines of code.

Select lines of code and click the comment button

Select commented lines and click the uncomment button


Page |8

SNIPPET & SHORTCUT KEYS

Snippet and shortcut keys can help save time while coding in Visual Studio. With snippet keys,
enter only a few letters or a keyword and then press tab twice to insert a code fragment.

Example: cw (tab) (tab)

// cw (tab)(tab) : Type cw and then press the tab key twice, the line below will display
Console.WriteLine();

Snippet & Shortcut Keys Result


cw (tab) (tab) Console.WriteLine();

while (tab) (tab) while (true)


{
}
for (tab) (tab) for (int i = 0; i < length; i++)
{
}
foreach (tab) (tab) foreach (var item in collection)
{
}
do (tab) (tab) do
{
} while (true);

prop (tab) (tab) public int MyProperty { get; set; }


(F5) Will start debugging

(ctrl) + (F5) Will start without debugging


Page |9

VARIABLES AND DATA TYPES

A variable is a named location in computer memory that holds information for later use. The
information within the variable can change or can be used when needed. Think of a variable as a box
that has been named; the contents within the box can change, but the box name stays the same.

The contents within a variable can have different data types. The data type declares what type
of information is going to be contained within the variable. There are many kinds of data types, such as a
string for text (“Hello World”) or an integer for numbers (54) with which mathematical calculations can
be performed.

In the example below, a variable of data type string is declared with a variable name of
“myStringName”. Declaring a variable can be thought of as creating an empty box that is named.

Example: Declare a variable

string myStringName;

Data Type Name

Example: Declare a variable and assign a value

string myStringName = "Hello";

Data Type Name Value

The variable “myStringName” now contains the value “Hello” within it. In the example below,
the value is changed to “Hello again”. Notice in the example below, the data type is not declared when
changing the value. Once the data type is declared, it is not declared again.

Example: Assign a new value

myStringName = "Hello again";


P a g e | 10

Example: Declare a variable and assign an integer value

int myIntName = 2 + 3; // myIntName is now 5

A string puts the two values together; an integer adds them together.

When declaring certain numeric data types, such as a float or a decimal (see page 11), it is
required to put a character behind the value. The example below demonstrates this.

Example: Numeric data types

int number1 = 5;
float number2 = 2.55f; // When declaring a float an "f" needs to be after the value
double number3 = 3.33;
decimal number4 = 4.66m; // When declaring a decimal an "m" needs to be after the value

It is recommended to be specific when declaring data types to avoid confusion. However, it is


possible to use the data type var and the compiler will attempt to figure out which data type to use.

Example: var

var theName = "hello"; // Declares a string and assigns value "hello"


var thenumber = 5; // Declares an int and assigns value 5
P a g e | 11

Every data type uses a specific amount of memory when declared. The smallest measurement is
a bit, and eight bits make up a byte. The chart below lists a few of the most common data types along
with how many bytes they use, their range, and an example of their data.

Data Types Bytes Range Example

byte 1 0 to 255 7

short 2 -32,768 to 32,767 -10

int 4 -2,147,483,649 to 2,147,483,647 12

long 8 -9,233,372,036,854,775,808 to 9,233,373,036,854,775,807 -54

sbyte 1 -128 to 127 5

ushort 2 0 to 65,535 7

uint 4 0 to 4,294,967,295 9

ulong 8 0 to 18,446,744,073,709,551,615 11

float 4 Represents a floating point value up to 7 digits 12.3

double 8 Represents a floating point value up to 16 digits 12.35

decimal 16 Represents a floating point value up to 29 significant digits 12.356

bool 1 Logical Boolean type (can only be True or False) True

char 2 A single Unicode character H

string varies A sequence of characters Hello

Integral types can be signed types or unsigned types. A signed type value can be positive or negative
and unsigned types can only be positive values. For example, a short, which is a signed type, can have a
value from -32,768 to 32,767. However, if negative numbers are not included, then the positive
numbers will double when making it unsigned. Using the unsigned data type for short (which is ushort),
the range will become 0 to 65,535
P a g e | 12

NAMING CONVENTIONS

Using proper naming and capitalization techniques can greatly increase the readability of code.
In C# the two popular capitalization techniques are Camel Casing and Pascal Casing for naming
variables, classes, methods, etc.

• Camel Casing: The first letter of the first word is lowercase, and all subsequent words
start with a capital letter.
• Pascal Casing: The first letter of every word is capitalized.

Example: Camel Case

int myFavoriteNumber = 7;

Use Camel Casing for local variables and arguments. Pascal Casing is used in most other
situations. While moving ahead in this book take notice of which casing technique is used.

Example: Pascal Case

public void MyMethodName() { }

Names should not include hyphens, spaces, non-alphanumeric characters, and they do not start
with a numeric number. The name should also be self-documenting. For example, instead of calling a
variable “variable1”, which has no meaning, it should be “scoreTotal”, which describes what the variable
is.
P a g e | 13

OPERATORS

The following is a sample of common operators used in C#.

Arithmetic operators perform a mathematical function.

+ Add
- Subtract
Arithmetic + - * / % * Multiply
/ Divide
% Remainder

Example: 5 + 1 // Output: 6
Assignment operators assign a value
Assignment = += -= *= /= %=
Example: X = 5 // X is assigned the value 5

Relational operators are used to compare values

== Equality (equal to)


!= Inequality (Not equal to)
Relational == != < > <= >= < Less than
> Greater than
<= Less than or equal
>= Greater than or equal

Example: X == 5 // Compares to see if X is equal to 5


Increases or decreases a value
Increment/Decrement ++ --
Example: X++ // Increases the value by 1
The plus sign will combine the items (not
mathematically)
String Concatenation + Example: 5 + 4 // Output: 54
Example: "Hi" + " John" // Output: Hi John

&& checks if both conditions are true


Example: (5 == X) && (6 == Y)
Conditional && ||
|| checks if either condition is true
Example: (5 == X) || (6 == Y)
P a g e | 14

INPUT & OUTPUT

Console applications are great for demonstrating computer concepts, which is why this book
focuses on them. They can easily output text and accept user input.

“Write” and “WriteLine” can both be used to output text in a Console application. The example
below demonstrates how to enter text between the quotes for it to display on the console.

Example: Output text

Console.Write("Hello "); // Write does not append a new line when finished
Console.Write("World!"); // Output: Hello World!

Console.WriteLine("Hello "); // WriteLine appends a new line when finished


Console.WriteLine("World!"); // Output: Hello
// World!

Below is a brief description of what each part of the above code represents.

Selects the Console Class (Classes


The text we want to output/display on the console
covered in a later section)

Console.WriteLine("Hello World!");

Tells the console to output text

“ReadLine” is used to input text in a Console application. “ReadLine” waits until text is entered
in the Console application and for the “Enter” key to be pressed.

Example: Input text

Console.ReadLine();

Example: Assign user input to a variable

string saveToVariable = Console.ReadLine();

User input from “Console.ReadLine()” is always a string. If the variable needs to be an integer,
for example, you would need to convert it from string to int (covered later in the “Parse and TryParse”
section).
P a g e | 15

There is a way to shorten the code from having to type “Console.WriteLine” to just “WriteLine”.
When creating a Console application, there is already some default code created. At the top of the
default “Program.cs” page, there is “using System;”. Add “using static System.Console;” below
“using System”. A more detailed explanation on this topic is covered later in “Namespaces & Using
Directives”.

Example: ReadLine and WriteLine without using “Console.”

ReadLine();
WriteLine(“Console. is no longer needed!”);

There are several different techniques to output data. In the examples below, the same
information is displayed in multiple ways. The last example uses the dollar sign before the quotes. This
denotes the usage of string interpolation. String interpolation is a feature that was introduced in C# 6; it
helps provide a more readable and convenient syntax and is the format this book will use going forward.

Full Example: Variables displayed in multiple ways

using static System.Console;

class ExampleOutput
{
static void Main(string[] args)
{
string todaysDay = "Tuesday";

WriteLine(todaysDay); // Output: Tuesday

WriteLine("Today is " + todaysDay); // Output: Today is Tuesday

WriteLine("Today is {0}", todaysDay); // Output: Today is Tuesday

WriteLine($"Today is {todaysDay}"); // Output: Today is Tuesday

ReadLine();
}
}
P a g e | 16

Escape characters are a special sequence of characters that are used to display something
different than the exact interpretation. For example, entering in quotes within “Writeline(“ ”Hello” ”)”
quotes will cause an issue. To get around this issue, use a backslash.

Example: Escape character for quote

WriteLine("Add a backslash before a quote \"Hello\"");


// Output: Add a backslash before a quote "Hello"

Escape characters can also be useful for starting a new line (“\n”), tab (“\t”) content, and many
other options.

Example: Tab and Newline

WriteLine("\t Hello \n World");


// Output: Hello
// World

The “@” symbol can be used before text to make the entire string ignore escape characters; the
technical name for this is verbatim string literal. This is often helpful with file names which would
require a lot of double backslashes (“//”).

Example: File name with backslashes compared to file name with “@” symbol

WriteLine("C:\\Users\\ComputerUser\\Desktop\\AFile.doc"); // with backslashes


WriteLine(@"C:\Users\ComputerUser\Desktop\AFile.doc"); // with @ symbol
P a g e | 17

CASTING

The conversion from one type to another is called typecasting, usually referred to as casting.
The two types of casting are implicit casting and explicit casting.

• Implicit casting occurs without specific instructions saying to cast. In most cases this will occur
automatically when going from a narrow type to a wider type with no loss of data.
• Explicit casting occurs because instructions stated for the casting to happen. Going from a wider
type to a narrow type generally requires explicit casting to acknowledge there may be loss of
data.

When adding numbers together they both must be the same type. In the example below, a short
and an int are added together using implicit casting. There is no chance of data loss because a short is
going from a narrow type to a wider type. A short is numbers -32,768 to 32,767, and an int is numbers -
2,147,483,649 to 2,147,483,647.

Example: Implicit casting

short num1 = 50;


int num2 = 600;
int sum = num1 + num2; // num1 is implicitly cast to int

Example: Explicit casting

decimal num1 = 50.1234m;


int num1CastToInt = (int)num1; // Explicitly cast to int. Data was lost (.1234)
int num2 = 2;
int sum = num1CastToInt + num2; // Output: 52

Casting is ideal for going from similar data types, such as short to int. However, if you need to convert
from string to an int, that is covered in the upcoming “Parse and TryParse” section in this book.
P a g e | 18

IF, ELSE IF, AND ELSE STATEMENTS

Decision-making is an important part of computer programs. The “if”, “else if”, and “else”
statements identify which statement to run based on the value of a Boolean (true or false) expression.
The visual example below asks the question “Is today Monday?”; it must have a true or false answer.

Is today
True False
Monday?

Today is NOT
Today is Monday
Monday

The code within an “if” statement will only execute if the condition is true. In the example below
there is an “if” statement with an equality operator which is “==”. In a previous section called
“Operators”, there is a list of relational operators that can be used within “if” statements.

Example: “If” statement

if ("Monday" == "Monday")
{
// Code within the curly brackets will execute because Monday equals Monday is TRUE
}

“If” statements should contain at least one variable. In the example above, Monday will always equal
Monday so there is no reason to use an “If” statement.

Example: “If” statement with variable

string todaysDay = "Monday";

if (todaysDay == "Monday")
{
// Code within the curly brackets will execute because Monday equals Monday is TRUE
}
P a g e | 19

Using an “else” statement after an “if” statement is sort of a catch all. Meaning that if the “if”
statement is not true, execute the code within the “else” statement.

Example: “If” and “else” statement

string todaysDay = "Tuesday";

if (todaysDay == "Monday") // This will NOT execute, todaysDay does not equal Monday
{
WriteLine("Today is Monday");
}
else // This WILL execute, the previous if statement was not true
{
WriteLine("Today is NOT Monday"); // Output: “Today is NOT Monday”
}

Use an “else if” statement after an “if” statement to test additional conditions to be true. Only
one “if” statement and one “else” statement can be used. However, multiple “else if” statements are
allowed. As soon as an “if” or “else if” statement is true, only the code within that code block is
executed. Any additional statements following that one will not execute even if they are true. The order
in which the “else if” statements are placed is important.

Example: “If” “else if” and “else” statement

string todaysDay = "Tuesday";

if (todaysDay == "Monday") // This will not execute, todaysDay does not equal Monday
{
WriteLine("Today is Monday");
}
else if (todaysDay == "Tuesday") // This will execute, todaysDay equals Tuesday
{
WriteLine("Today is Tuesday"); // Output: “Today is Tuesday”
}
else if (todaysDay == "Wednesday")
{
WriteLine("Today is Wednesday");
}
else // This will not execute, a previous If statement was true
{
WriteLine("Today is NOT Monday, Tuesday, or Wednesday");
}
P a g e | 20

The curly brackets following a condition are not always needed. If the statement is exactly one
line of code they are not needed. They are only required for multiple lines of code.

Example: Curly brackets

string todaysDay = "Tuesday";

if (todaysDay == "Monday")
WriteLine("Today is Monday");
else if (todaysDay == "Tuesday")
WriteLine("Today is Tuesday"); // Output: “Today is Tuesday”
else if (todaysDay == "Wednesday")
{
// Curly brackets are needed if there are more than 1 statement following a condition
WriteLine("Today is Wednesday");
WriteLine("It is the middle of the work week!");
}
else
WriteLine("Today is NOT Monday, Tuesday, or Wednesday");

Full Example: “If” “else if” and “else” statement

using static System.Console;


class ExampleIFElseIFElse
{
static void Main(string[] args)
{
int myValue = 5;

if (myValue <= 3)
WriteLine("The value is low");
else if (myValue >= 7)
WriteLine("The value is high");
else // The else value is true because the first 2 conditions were not met
WriteLine("The value is in the middle"); // Output: The value is in the middle

ReadLine();
}
}
P a g e | 21

“If” statements can be nested, meaning they can be put inside other “if” statements.

Example: Nested statement

bool gameActive = true;


int health = 40;

if (gameActive == true)
{
WriteLine("Game is Active!");

if (health == 100) // Nested "if" statement


WriteLine("You are in perfect health!");
else
WriteLine("You have been hurt");
}

Conditional operators (covered in the “Operators” section) are commonly used in “if” and “else
if” statements. In the example below the “&&” operator is used, meaning that both conditions must be
true.

Example: Conditional operator “AND” && (both conditions must be true)

bool gameActive = true;


string player = "Adam";

if (gameActive == true && player == "Adam")


WriteLine("The game is active AND Adam is alive!” );

Example: Conditional operator “OR” || (either condition can be true)

bool gameActive = true;


string player = "Adam";

if (gameActive == true || player == "Adam")


WriteLine("The game is active OR Adam is Alive!");
P a g e | 22

SWITCH

The switch statement is like an “if” statement; it is useful if you have several options from which
to choose. Anything that can be done with a switch statement can also be done with an “if” statement.
Select whichever makes the code easiest to understand.

With switch statements each option is a case, and there is also a default option if none of the
cases match (like an “else” statement). Within the case curly brackets “{}” are not needed. A case is
ended with “break;”.

Example: Switch

int optionPicked = 3;

switch (optionPicked)
{
case 1:
WriteLine("My number is 1");
break;
case 2:
WriteLine("My number is 2");
break;
case 3: // case 3 is true
WriteLine("My number is 3"); // Output: My number is 3
break;

default:
WriteLine("Other option");
break;
}

If there is code within a case, “break” must be used. If the code within a case is empty the case
will “fall through” until a “break” is reached. In the example below several cases are combined into one
result.

Example: Switch Case “fall through”

int optionPicked = 2;

switch (optionPicked)
{
case 1:
case 2:
case 3:
// The text below will display
WriteLine("Low number selected"); // Output: “Low number selected”
break;
case 4:
P a g e | 23

case 5:
WriteLine("Medium number selected");
break;
default:
WriteLine("Other number selected");
break;
}

Full Example: Switch

using static System.Console;

class ExampleSwitch
{
static void Main(string[] args)
{
WriteLine("Type the name of a number: One, Two, Three or Four");
string num1 = ReadLine();

switch (num1)
{
case "One":
case "Two":
WriteLine("Picked number 1 or 2");
break;
case "Three":
WriteLine("Picked number 3");
break;
case "Four":
WriteLine("Picked number 4");
break;
default:
WriteLine("Entered incorrect input");
break;
}

ReadLine();
}
}
P a g e | 24

PARSE & TRYPARSE

Parse and TryParse both attempt to convert one data type to another. The example below
attempts to convert a string to an int. When using Parse, be 100% certain that it will convert
successfully, otherwise the program will crash. For example, if a user is asked to input a numeric number
and they type the word “Hello”, the program will crash.

TryParse is a safer approach because it checks if the value can convert to a numeric value. If
TryParse cannot convert the value, it sets the value to 0.

Example: Parse from a string to an int

string text0 = "6";


int text0Int = int.Parse(text0);
// This works, however if text0 was “Hello” or "six" the program would crash

Example: TryParse from a string to an int

string text1 = "7";


int text1Int;
int.TryParse(text1, out text1Int);
// If text1 was “Hello” or "seven" the program would display 0 by default and NOT crash

Example: TryParse using an Inline Out Variable (this is a new feature introduced in C# 7)

string text3 = "10";


int.TryParse(text3, out int num3);
// With this approach, it is not needed to declare the num3 int beforehand

Example: TryParse using an “If” statement

string text2 = "8";


if (int.TryParse(text2, out int text2Int))
WriteLine($"TryParse was successful, converted a String to an Int: {text2Int}");
else
WriteLine("TryParse failed. text2Int set to the default which is 0.");
P a g e | 25

Full Example: Parse

using static System.Console;

class ExampleParse
{
static void Main(string[] args)
{
WriteLine("Enter a number");
string text1 = ReadLine();
// Very unsafe to do this because if the user enters incorrect information the
// program will crash. Use TryParse instead.
int num1 = int.Parse(text1);

WriteLine("Enter a second number");


// ReadLine can be used directly in Parse to accept user input
// Very unsafe to do this because is the user enters incorrect information the
// program will crash. Use TryParse instead.
int num2 = int.Parse(ReadLine());

WriteLine($"The sum of first number {num1} and second number {num2} is {num1 + num2}");

// The Parse below is safe because you are 100% sure 6 will convert into an int
string text3 = "6";
int num3 = int.Parse(text3);

ReadLine();
}
}

Full Example: TryParse

using static System.Console;

class ExampleTryParse
{
static void Main(string[] args)
{
WriteLine("Enter a number");
string text1 = ReadLine();
int.TryParse(text1, out int num1);

WriteLine("Enter a second number");


// ReadLine can be used directly in the TryParse to accept user input
int.TryParse(ReadLine(), out int num2);

WriteLine($"The sum of first number {num1} and second number {num2} is {num1 + num2}");
ReadLine();
}
}
P a g e | 26

LOOPS

A Loop can repeat a block of code multiple times. The four main types of loops are While, Do-
While, For, and ForEach.

A while loop executes a block of code while the condition is true.

Is number less Output number


True
than 10? and add 1

False

Example: While Loop

int number = 0;

while (number < 10)


{
Write(number);
number++; // number++ is equivalent to using “number = number + 1”
}
// Output: 0123456789

The above code will loop and output numbers from 0 to 9. Every time the loop executes it
increases the value by 1 until the number is equal to 10.

A Do-While Loop evaluates the condition after the loop has executed, meaning the code block
will always execute at least once.

Example: Do-While Loop

int number = 0;

do
{
Write(number);
number++;
}
while (number < 10);

// Output: 0123456789
P a g e | 27

A For Loop is generally used when the number of iterations needed is known. The starting value,
test conditions, and the increment/decrement are all set in one compact line of code.

Example: For Loop

int number = 10;

for (int i = 0; i < number; i++)


Write(i); // Output: 0123456789
// Curly brackets {} are not needed if a loop is only 1 line of code.

A ForEach Loop is used for collections of items, such as arrays (arrays covered in next section).

Example: ForEach Loop

int[] numbers = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

foreach (int number in numbers)


Write(number); // Output: 0123456789
// Curly brackets {} are not needed if a loop is only 1 line of code.

Full Example: While and For loops

using static System.Console;

class ExampleLoop
{
static void Main(string[] args)
{
WriteLine("Enter a number to count up to it using a While loop");
int.TryParse(ReadLine(), out int num1);

int counter = 0;
while (counter <= num1)
{
WriteLine(counter);
counter++; // number++ is equivalent to using “number = number + 1”
}

WriteLine("Enter a number to count up to it using a For loop");


int.TryParse(ReadLine(), out int num2);

for (int counter2 = 0; counter2 <= num2; counter2++)


WriteLine(counter2);

ReadLine();
}
}
P a g e | 28

Putting a loop within another loop is called a nested loop. The outer loop is called the parent
loop, and the loop within is the child loop. In the example below the outer loop controls when to exit
the game.

Example: Nested loop

string playGame = "";


int counter = 0;

while (playGame != "Quit") // “!=” means not equal to


{
while (counter < 5)
{
counter++;
WriteLine($"This number is from the nested loop {counter}");
}

counter = 0;
WriteLine("Press Enter to display again or type Quit to exit.");
playGame = ReadLine();
}

Exit a loop early by using the break keyword. In the example below, the program is ended when
the user guesses the correct number.

Example: Break

string computerNumber = "5";


while(true) // Generally do not use a forever loop; this was used as an example for break
{
WriteLine("Guess what number I am thinking");
string guessedNumber = ReadLine();

if (guessedNumber == computerNumber)
break;
}

There is another keyword like break called continue. Instead of exiting the loop, continue goes
directly to the start of the loop to check the condition again. In the example below, continue is used to
skip the number 7.

Example: Continue

for (int i = 0; i < 10; i++)


{
if (i == 7) // Skip number 7
continue;
WriteLine($"Number: {i}");
}
P a g e | 29

ARRAYS

An array is a collection of data types of the same type; for example, an array could contain all
strings. Arrays can be looped over to display their items, sorted, and many other operations.

Use a set of square brackets “[]” after the datatype to declare an array. Arrays are usually
named with a plural word. In the example below, an array of strings is named “foods”.

Example: Declare array

string[] foods;

An array must be instantiated to use it. Instantiate means to “create an instance of”; this is
done using the “new” keyword. In the example below, the number 5 specifies how many items (often
referred to as elements) the array can hold.

Example: Instantiate array

string[] foods;
foods = new string[5];

Example: Instantiate and declare an array at same time

string[] foods = new string[5];

There are several ways to assign values to an array. It is important to point out that arrays start
at value 0 and not 1. A few examples of how to assign values are listed below:

Example: Assign and output values

// Example 1
string[] foods = new string[5];

foods[0] = "Pizza"; // Arrays start at value 0


foods[1] = "Burger";
WriteLine($"I want a {foods[0]} and {foods[1]}.");
// Output: I want a Pizza and Burger.

// Example 2
string[] drinks = new string[5] { "Pepsi", "Sprite", "", "", "" };
// The additional "" are holding the place for the remaining 3 items
WriteLine($"I want a {drinks[1]}."); // Output: I want a Sprite.

// Example 3
string[] cars = new string[] { "Ford", "Toyota" };
WriteLine($"I want a {cars[0]}."); // Output: I want a Ford.
P a g e | 30

// Example 4
string[] animals = { "Cat", "Dog" };
WriteLine($"I want a {animals[1]}."); // Output: I want a Dog.

Full Example: Display all items of an array using a foreach loop

using static System.Console;

class ExampleArrayForEachLoop
{
static void Main(string[] args)
{
string[] foods = { "Pizza", "Burger" };

foreach (string food in foods)


WriteLine($"The food item is {food}.");
// Output: The food item is Pizza.
// Output: The food item is Burger.

ReadLine();
}
}

Full Example: Sort and array length. The length property in this example is used to determine how many
loops should occur.

using System;
using static System.Console;

class ExampleArraySort
{
static void Main(string[] args)
{
int[] someNumbers = { 21, 22, 50, 3, 6 };

Array.Sort(someNumbers); // Sorts the numbers in ascending order

// someNumbers.Length is the length of the array, in this case 5


for (int i = 0; i < someNumbers.Length; i++)
Write($"{ someNumbers[i]} "); // Output: 3 6 21 22 50
}
}

The above example uses “Array.Sort()”. Sort is a method within the Array class that organizes
the contents of an array numerically and alphabetically. The Array class has other methods as well, such
as “Array.Reverse()”.
P a g e | 31

ARRAYS: 2-D AND 3-D

In the previous section, the arrays have all been one-dimensional arrays. It is possible to make
two-dimensional arrays, three-dimensional arrays, and so on. These Multidimensional arrays can be
useful; the example below shows a two-dimensional array for a game map. Two values are needed for a
2-D array (row and column). Indicate a 2-D array by entering a comma between the square brackets.

Example: Declare a 2-D array

string[,] myGameMap = new string[,]


{
// Empty 2D array
};

Full Example: 2-D array

using static System.Console;

class Example2DArray
{
static void Main()
{
// 2-D Array for a game map
// Place a comma between the brackets [,] to use a 2-D Array
string[,] myGameMap = new string[,]
{
{"Scary Room1", "Safe Room2", "Safe Room3"}, // Row 0
{"Dangerous Room4", "Safe Room5", "Safe Room6"}, // Row 1
{"Safe Room7", "Scary Room8", "Safe Room9"} // Row 2
};

// The first number is the row, the second number is the column
// Keep in mind that array values start at 0
WriteLine(myGameMap[0, 0]); // Output: Scary Room1
WriteLine(myGameMap[1, 0]); // Output: Dangerous Room4
WriteLine(myGameMap[2, 2]); // Output: Safe Room9
}
}
P a g e | 32

While a 2-D array can be thought of as making a square with width and height (row and
column), a 3-D array can be thought of as making a cube to include depth (row, column, and depth).
When creating a 3-D array, add an additional comma between the square brackets to indicate the 3-D
array is being created.

Example: Declare a 3-D array

string[,,] arrayExample3D = new string[,,]


{
// Empty 3D array
};

Full Example: 3-D array

using static System.Console;

class Example3DArray
{
static void Main()
{
// Add 2 commas between the square brackets to indicate a 3-D array
string[,,] arrayExample3D = new string[,,]
{
{{"This is ", "a 3-D "}, // Row 0, Column 0, Depth is 0 or 1
{"array ", "example."} // Row 0, Column 1, Depth is 0 or 1
},
{{"They can ", "become "}, // Row 1, Column 0, Depth is 0 or 1
{"complex ", "very quickly."} // Row 1, Column 1, Depth is 0 or 1
},
};
// [Row, Column, Depth]
Write(arrayExample3D[0, 0, 0]); // Output: This is
Write(arrayExample3D[0, 0, 1]); // Output: a 3-D
Write(arrayExample3D[0, 1, 0]); // Output: array
Write(arrayExample3D[0, 1, 1]); // Output: example.
WriteLine(); // Add a space
Write(arrayExample3D[1, 0, 0]); // Output: They can
Write(arrayExample3D[1, 0, 1]); // Output: become
Write(arrayExample3D[1, 1, 0]); // Output: complex
Write(arrayExample3D[1, 1, 1]); // Output: very quickly

// Output:
// This is a 3-D array example
// The can become complex very quickly
}
}
P a g e | 33

ARRAYS: JAGGED

A jagged array is when arrays of various sizes are put inside an array.

Example: Declare jagged array

string[][] jaggedEx = new string[3][];

Example: Assign arrays to an array.

jaggedEx[0] = new string[2]; // 2 element array


jaggedEx[1] = new string[5]; // 5 element array
jaggedEx[2] = new string[8]; // 8 element array

Example: Declare jagged array and assign arrays

string[][] jaggedEx = new string[3][] { new string[2], new string[5], new string[8] };

Example: Assign value to array

jaggedExample[1][4] = "Store this string in Array 1, Element 4";

Full Example: Jagged array

using static System.Console;


class JaggedExample
{
static void Main(string[] args)
{
string[][] classStudents = new string[2][] { new string[2], new string[1] };

classStudents[0][0] = "Sergio"; // In classroom student


classStudents[0][1] = "Jonathan"; // In classroom student
classStudents[1][0] = "Aria"; // Online student

WriteLine($"{classStudents[0][0]} and {classStudents[0][1]}: Classroom students");


WriteLine($"{classStudents[1][0]}: Online student");

// Output: Sergio and Jonathan are in classroom students


// Output: Aria is an online student
ReadLine();
}
}
P a g e | 34

METHODS

A method is a group of reusable code that carries out a task. To use a method, define the
method and call the method. When defining a method, declare the elements of its structure.

The following is an example of the method syntax:

Access modifier Return Type Parameters

public static int Add2Numbers(int num1, int num2)

Static Modifier Name

• Access Modifier: The access modifier determines the visibility of the method (which classes
have access to them). Examples include public, internal, private, and protected. Access
modifiers are optional.
• Static Modifier: Static methods are shared by all instances of the class, meaning the method can
be accessed directly from the class name (static and classes are covered in the Classes section).
Static modifiers are optional.
• Return Type: A method can return a value type (Int, String, Bool, etc.) or return void if the
method does not return anything when called. A return type must be specified.
• Name: Method names are required.
• Parameters: Arguments (values) are passed to parameters in methods. Parameters are optional.

Example: Method that returns no values

public static void Countdown()


{
for (int i = 3; i > 0; i--)
WriteLine(i);
}

static void Main(string[] args)


{
Countdown(); // Call the method
// Output: 3 2 1
}
P a g e | 35

Methods can also have parameters. Parameters pass values from arguments into methods. The
parameter refers to the name and the arguments are the values sent to the method. The example below
notes where each is located.

Example: Method that returns no values and accepts a parameter

public static void WelcomeMessage(string name) // Parameter is “name”


{
WriteLine($"Hello, {name}"); // Output: Hello, Adam
}

static void Main(string[] args)


{
WelcomeMessage("Adam"); // Call the method and pass the argument “Adam”
}

Parameters can also be optional by giving them a default value. In the example below, following
the parameter “name”, the default value “Guest” is assigned to the parameter, making it optional.

Full Example: Method with an optional parameter

using static System.Console;

class OptionalParemeterExample
{
public static void WelcomeMessage(string name = "Guest")
{
WriteLine($"Hello, {name}");
}

static void Main(string[] args)


{
WelcomeMessage(); // Output: Hello, Guest
WelcomeMessage("Adam"); // Output: Hello, Adam

ReadLine();
}
}
P a g e | 36

Example: Method that returns a value and accepts a parameter

public static int Add3Numbers(int num1, int num2, int num3)


{
int result = num1 + num2 + num3; // Add 2 parameters together
return result; // Return the value
}

static void Main(string[] args)


{
int a = 5, b = 2; // Tip: Data types of the same type can be declared on the same line

int combinedValue = Add3Numbers(a, b, 8);


WriteLine($"{a} + {b} + 8 = {combinedValue}");
// Output: 5 + 2 + 8 = 15

// The code below demonstrates a method call within WriteLine.


WriteLine($"{a} + {b} + 6 = {Add3Numbers(a, b, 6)}");
// Output: 5 + 2 + 6 = 13
}

Full Example: Passing an object to a method (objects and classes covered in the Classes section)

using static System.Console;

class MethodObjectExample
{
public class Player
{
public string Name { get; set; }
public int Health { get; set; } = 100;
}

public static class Combat


{
public static void FightBattle(Player thePlayer)
{
thePlayer.Health = thePlayer.Health - 20; // Decrease health by 20
}
}

static void Main(string[] args)


{
Player player1 = new Player { Name = "ABC", Health = 100 };

Combat.FightBattle(player1);
WriteLine($"{player1.Name} has {player1.Health} health"); // Output: ABC has 80 health
}
}
P a g e | 37

Arguments can be passed by reference, not by value. Pass references using the ref keyword;
changes made in a method for a reference will affect the original value outside the method.

Full Example: Passing a reference to a method

using static System.Console;

class ExampleMethodPassReference
{
static void PlayerDamaged(ref int playerHealth)
{
playerHealth = playerHealth - 20;
}

static void Main(string[] args)


{
int playerHealth = 100;
PlayerDamaged(ref playerHealth); // Pass playerHealth as reference parameter.
WriteLine(playerHealth); // Output: 80

ReadLine();
}
}
P a g e | 38

METHODS: OVERLOAD

Overloading a method occurs when methods have the same name but different signatures. The
compiler is smart enough to know which method to use based on what is being called.

Example: Overload Method

public static void DisplayMe()


{
WriteLine("Result: Nothing to Display");
}

public static void DisplayMe(string theString)


{
WriteLine($"The string {theString} was called");
}

Full Example: Overload Method

using static System.Console;


class ExampleOverloadMethod
{
public static void DisplayMe()
{
WriteLine("Result: Nothing to Display");
}

public static void DisplayMe(string theString)


{
WriteLine($"The string {theString} was called");
}

public static void DisplayMe(int theInt)


{
WriteLine($"The int {theInt} was called");
}

public static void DisplayMe(int theInt1, int theInt2)


{
int tempInt = theInt1 + theInt2;
WriteLine($"The total of those 2 numbers is {tempInt}");
}

static void Main(string[] args)


{
DisplayMe(); // Output: “Result: Nothing to Display”
DisplayMe("Hello World"); // Output: “The string Hello World was called”
DisplayMe(215); // Output: “The int 215 was called”
DisplayMe(215, 500); // Output: “The total of those 2 numbers is 715”
ReadLine();
}
}
P a g e | 39

METHODS: RECURSION

The concept of Recursion is when something calls itself. When a method calls itself, it is
referred to as a recursive method.

Example: Recursive method

public static double AMethod()


{
// Method calls itself
return AMethod(); // Note: This example would crash a program because it would never end
}

Full Example: Recursive method

using static System.Console;

class ExampleRecursive
{
public static string VerifyWord()
{
WriteLine("Choose: Up, Down");
string direction = ReadLine();

if (direction == "Up" || direction == "Down")


return direction;

return VerifyWord(); // Method calls itself


}

static void Main(string[] args)


{
string directionToGo = VerifyWord();
ReadLine();
}
}
P a g e | 40

Full Example: Recursive method - Advanced

using static System.Console;

class ExampleRecursive
{
// A factorial is the multiplication of every number below it.
// For example: The factorial of 4 equals (1 * 2 * 3 * 4 = 24)
public static double Factorial(int number)
{
if (number == 0)
return 1;

return number * Factorial(number - 1); // Method calls itself


}

static void Main(string[] args)


{
int numberEntered = 4;
double factorial = Factorial(numberEntered);

WriteLine($"factorial of {numberEntered} = {factorial.ToString()}");

ReadLine();
}
}

When a method invokes another method and the resulting method eventually invokes the
original method, this is called indirect recursion.

Full Example: Indirect recursion

using System;
using static System.Console;

class IndirectRecursionExample
{

public static bool IsOdd(int numberSelected)


{
if (numberSelected == 0)
return false;

return IsEven(Math.Abs(numberSelected) - 1);


}

public static bool IsEven(int numberSelected)


{
if (numberSelected == 0)
return true;

return IsOdd(Math.Abs(numberSelected) - 1);


}
P a g e | 41

static void Main(string[] args)


{
int number = 7;
bool theAnswer = IsOdd(number);
WriteLine($"Is the number {number} odd? {theAnswer}");

ReadLine();
}
}
P a g e | 42

METHODS: NAMED ARGUMENTS

Using named arguments helps clarify the parameters used when calling a method. Without named
arguments a long list of numbers can quickly become confusing.

Example: Calling a method with a named argument

AMethodName(Person: "Matt");

Named argument

Full Example: Named arguments

using static System.Console;

class ExampleNamedArguments
{
static void Main(string[] args)
{
// Without named arguments it is not clear what the numbers represent.
CharacterDescription("Bob", 42, 72, 61);

CharacterDescription("Bob", 42, 72, level: 61); // With 1 named argument


CharacterDescription("Bob", age: 42, height: 72, level: 61); // With 3 named arguments

// With all named arguments


CharacterDescription(name: "Bob", age: 42, height: 72, level: 61);

// TIP: Methods can be entered on multiple lines for additional clarity


CharacterDescription(name: "Bob",
age: 42,
height: 72,
level: 61);

ReadLine();
}

public static void CharacterDescription(string name, int age, int height, int level)
{
WriteLine($"{name}: level {level}, {age} years old, and height of {height} inches.");
}
}
P a g e | 43

CLASSES

A class is a group of related methods and variables with common attributes. A class can be
thought of as a “blueprint” or “template” and objects are instantiated (created) from it. A single class
can instantiate an infinite number of objects.

Example: Create a class

class Card
{
// Note: The upcoming section “Get-Set Properties” discusses how to properly handle
// fields in a class. Until then, public fields will be used.

public string name;


public int value;
public string suit = "Heart"; // Set a default value of "Heart"
}

Example: Instantiate an object

Card Card1 = new Card();

Example: Assign values to an object

Card1.name = "King";
Card1.value = 13;

Example: Instantiate an object and assign values

Card Card2 = new Card


{
name = "Nine",
value = 9,
suit = "Spade"
};

Example: Display output from an object

WriteLine($"Card1 Suit: {Card1.suit} Name: {Card1.name} Value: {Card1.value}");


WriteLine($"Card1 Suit: {Card2.suit} Name: {Card2.name} Value: {Card2.value}");
P a g e | 44

Full Example: Class

using static System.Console;


// The class named “Card” has attributes for a playing card
class Card
{
public string name;
public int value;
public string suit = "Heart";

public void DisplayCard()


{
WriteLine($"Card Suit: {suit} Name: {name} Value: {value}");
}
}

class ExampleClass
{
static void Main(string[] args)
{
// Example 1: Instantiate an object
Card Card1 = new Card ();

// Assign values to the object


Card1.name = "King";
Card1.value = 13;

// Example 2: Instantiate an object and assign values


Card Card2 = new Card
{
name = "Nine",
value = 9,
suit = "Spade"
};

Card1.DisplayCard(); // Output: Card Suit: Heart Name: King Value: 13


Card2.DisplayCard(); // Output: Card Suit: Spade Name: Nine Value: 9
ReadLine();
}
}

In the example above, the Card class contains the method “DisplayCard()”. In the previous
examples, all methods have started with “public static”. This method leaves out the static keyword.
Static methods are accessed through the class name directly. In this example, the method is accessed
through instances of the class instantiated called “Card1” and “Card2”.

Example: Static method call vs instance method call

Card.DisplayCard(); // If the method was static, it would be called like this


Card1.DisplayCard(); // If the method was an instance, it would called like this
P a g e | 45

Example: A list using a class as the type

// DeckOfCards List holds objects of type Card (Class created in previous examples)
List<Card> DeckOfCards = new List<Card>()
{
// Create objects of each card needed for a deck of cards
new Card {name = "Ace", value = 1, suit = "Heart"},
new Card {name = "Two", value = 2, suit = "Heart"},
new Card {name = "Three", value = 3, suit = "Heart"}
// Continue adding cards...
};

// Additional way to add cards to a list


DeckOfCards.Add(new Card() { name = "Nine", value = 9, suit = "Spade" });
P a g e | 46

CLASSES: CONSTRUCTOR

A constructor is essentially a method in a class that executes when the object is instantiated.
The constructor will have the same name as the class and can be overloaded. A constructor cannot have
a return type.

Example: Constructor

public class Person


{
public Person()
{ // Empty constructor }
}

Full Example: Constructor

using static System.Console;

public class Person


{
public string Name { get; private set; }

public Person() // Constructor with no parameters


{ Name = "Empty"; }

public Person(string firstName) // Constructor with one parameter


{ Name = firstName; }

public Person(string firstName, string lastName) // Constructor with two parameters


{ Name = $"{firstName} {lastName}"; }
}

class ConstructorExample
{
static void Main(string[] args)
{
Person person1 = new Person(); // Call constructor with no arguments
WriteLine(person1.Name); // Output: Empty

Person person2 = new Person("Adam"); // Call constructor with one argument


WriteLine(person2.Name); // Output: Adam

Person person3 = new Person("Adam", "Seebeck"); // Call constructor with two arguments
WriteLine(person3.Name); // Output: Adam Seebeck

ReadLine();
}
}
P a g e | 47

CLASSES: STATIC

The keyword static in static classes denotes that the class is singular; you cannot create an
instance (object) of the class. In a static class all methods and fields must be static.

Example: Static class

static class OnlyOneHouse


{
// Fields must be static
public static string color = "Red";
}

Full Example: Static class

using static System.Console;

static class OnlyOneHouse


{
// default attributes for House class
public static int Height;
public static int Width = 5;
public static int Size = 25;
public static string Color = "Red";

public static void DisplayHouse()


{
WriteLine($"Size of House: {Size} and color {Color}");
}
}

class ExampleStaticClass
{
static void Main(string[] args)
{
OnlyOneHouse.Height = 10;
OnlyOneHouse.Size = OnlyOneHouse.Height * OnlyOneHouse.Width;

OnlyOneHouse.DisplayHouse(); // Output: Size of House: 50 and color Red


ReadLine();
}
}
P a g e | 48

GET-SET PROPERTIES

Previously in this book, fields have been declared public. However, fields should in general be
private and only allow access when needed. This is where Get-Set properties accessors Get or Set are
used to access or change data. Get-Set properties combine aspects of both fields and methods.

Example: Full way to declare a property

private string myProperty; // Declare a private field


public string MyProperty // Property is Public: it can be accessed from outside the class
{
get { return myProperty; } // Get retrieves the value from myProperty and returns it
set { myProperty = value; } // Set gives access to change private field myProperty
}

The “MyProperty” get section can return the private field value of “myProperty” and the set
section can assign a value to the private field “myProperty”. It is common to name the private field the
same name as the property except with a lower-case letter or with an underscore and then a lowercase
letter, for example “_myProperty”.

Full Example: Get-Set Property

using static System.Console;

public class Vehicle


{
private string car;
public string Car
{
get { return car; }
set { car = value; }
}
}

class ExampleGetSetPropeties
{
static void Main()
{
Vehicle brand = new Vehicle();

brand.Car = "Toyota"; // Use set in Car property to set private field car to “Toyota”
WriteLine(brand.Car); // Use get in Car property to get value of private field car
// Output: Toyota
ReadLine();
}
}
P a g e | 49

It is possible to add additional logic to a property. In the example below, logic within the get
verifies a number between 1-12 is entered, otherwise 0 is returned.

Full Example: Get-Set property with logic

using static System.Console;

public class Month


{
private int theMonth;
public int TheMonthVerify
{
get
{
// If a number is greater than 12 or less than 0 the value is set to zero.
if ((theMonth > 1) || (theMonth < 0))
theMonth = 0;

return theMonth;
}
set
{
theMonth = value;
}
}
}

class ExampleGetSetPropeties
{
static void Main()
{
Month TheMonth = new Month();

TheMonth.TheMonthVerify = 5;
WriteLine(TheMonth.TheMonthVerify); // Output: 5

TheMonth.TheMonthVerify = 13;
WriteLine(TheMonth.TheMonthVerify); // Output: 0

ReadLine();
}
}
P a g e | 50

There is a shorthand way, referred to as auto-implemented property, to create get-set


properties when no extra logic is needed. The syntax is a lot simpler, and it is no longer necessary to
create a private field as this is created behind the scenes.

Example: Shorthand way to declare a property (auto-implemented property)

public string MyProperty { get; set; }

Example: Assign a default value when declaring a property

public string MyProperty { get; set; } = 5;

Full Example: Get-Set Property shorthand way

using static System.Console;

public class Vehicle


{
public string Car { get; set; }
}

class ExampleGetSetPropeties
{
static void Main()
{
Vehicle brand = new Vehicle();

brand.Car = "Toyota"; // Use set in Car property to set private field car to “Toyota”
WriteLine(brand.Car); // Use get in Car property to get value of private field car
// Output: Toyota
ReadLine();
}
}

Using get-set properties gives the ability to define how accessible the property is. It may be
tempting to give all properties getters and setters, however in a lot of cases only one is necessary.
Always give as little access as possible.

Example: Get only property (read only)

public string MyProperty { get; }


// Leaving out “set” means you can retrieve information but cannot change the value
P a g e | 51

Another option is to change the accessibility of the set property. In the example below, set has
the private modifier before it, meaning it can only be changed within the class.

Example: Private set

public int CarID { get; private set; }

Full Example: Private set

using static System.Console;

public class Vehicle


{
public Vehicle(int theID)
{
CarID = theID;
}

public int CarID { get; private set; }


}

class ExamplePrivateSet
{
static void Main(string[] args)
{
Vehicle car1 = new Vehicle(54);
WriteLine(car1.CarID); // Output: 54

ReadLine();
}
}
P a g e | 52

When instantiating an object that contains properties you can assign values to them one at a
time or can assign multiple at the same time using object initializer syntax.

Example: Object initializer syntax

Vehicle car1 = new Vehicle { Brand = "Toyota", Color = "Red" };

Full Example: Object initializer syntax

using static System.Console;

public class Vehicle


{
public string Brand { get; set; }
public string Color { get; set; }
}

class ExampleObjectInitializerSyntax
{
static void Main(string[] args)
{
// Example: Object Initializer Syntax
Vehicle car1 = new Vehicle { Brand = "Toyota", Color = "Red" };

// Assign 1 at a time
Vehicle car2 = new Vehicle();
car2.Brand = "Ford";
car2.Color = "White";

ReadLine();
}
}
P a g e | 53

CLASSES: INHERITANCE

Classes can inherit from other classes, meaning they acquire all of another class’s features. With
class inheritance, the derived class acquires all the features from a base class. C# only supports single
inheritance, meaning it can only inherit one class at a time.

Example: Inheritance

public class ASecondClass : TheFirstClass


{
// ASecondClass inherits all the features from the base class TheFirstClass
}

Full Example: Inheritance

using static System.Console;

public class CarBaseClass


{
public string Brand { get; set; }
public int Wheels { get; } = 4;
}

public class CarSedanDerivedClass : CarBaseClass


{
public int Doors { get; } = 2;
}

class ExampleClassInheritance
{
static void Main(string[] args)
{
CarSedanDerivedClass Car1 = new CarSedanDerivedClass();
Car1.Brand = "Tesla";

// An object of CarSedanDerivedClass has inherited information from CarBaseClass


WriteLine($"A {Car1.Brand} has {Car1.Wheels} wheels and {Car1.Doors} doors");
// Output: A Tesla has 4 wheels and 4 doors

ReadLine();
}
}
P a g e | 54

C# only supports single inheritance; however, inheritance is transient, meaning it can form a
class hierarchy.

Full Example: Inheritance transient

using static System.Console;

class ExampleClassInheritanceTransient
{
public class BaseClassExample
{
public int TheBaseProperty { get; } = 5;
}

public class AClassExample : BaseClassExample


{
// empty class
}

public class BClassExample : AClassExample


{
// empty class
}

static void Main(string[] args)


{
BClassExample obj1 = new BClassExample();
// BClassExample still has access to BaseClassExample because inheritance is transient

WriteLine(obj1.TheBaseProperty); // Output: 5
}
}

Sealed classes prevent a class from being inherited. In some scenarios using a sealed class will
also provide a performance boost.

sealed class ExampleBaseClass


{
// This class cannot be inherited from
}
P a g e | 55

METHOD: VIRTUAL

To redefine a method in a derived class, use a virtual method. Virtual methods are redefined
using the “virtual” keyword in the base class and the “override” keyword in the derived class.

Example: Virtual method

public virtual void Sound()


{
WriteLine("Generic Noise");
}

Full Example: Virtual method

using static System.Console;

class Animal
{
public virtual void Sound()
{
WriteLine("Generic Noise");
}
}

class Dog : Animal


{
public override void Sound()
{
WriteLine("Bark");
}
}

class ExampleVirtualMethod
{
static void Main(string[] args)
{
Animal anyAnimal = new Animal();
ExampleShow1.Sound(); // Output: Generic Noise

Dog aDog = new Dog();


ExampleShow2.Sound(); // Output: Bark

ReadLine();
}
}
P a g e | 56

CLASSES: ABSTRACT

Abstract classes are commonly used for inheritance and cannot be instantiated. Abstract
methods within an abstract class must be contained in the child class or the program will not compile.
Virtual methods are not required in child classes.

Example: Abstract class

public abstract class Talk


{
// empty abstract class
}

Full Example: Abstract class

using static System.Console;

public abstract class Talk


{
// Abstract must be implemented in child class
public abstract void Greeting();

// Virtual is NOT required to be in child class but may be optionally overridden.


public virtual void Goodbye()
{
WriteLine("Goodbye!");
}
}

public class SpanishLanguage : Talk


{
public override void Greeting()
{
WriteLine("Hola");
}
}

class ExampleAbstractClass
{
static void Main(string[] args)
{
SpanishLanguage languageSelected = new SpanishLanguage();
languageSelected.Greeting(); // Output: Hola
languageSelected.Goodbye(); // Output: Goodbye!
}
}
P a g e | 57

CLASSES: PARTIAL

Partial classes can be split across two or more source files. Each file source will contain a section
of the class and all parts will be combined when the compiled. The “partial” keyword is used for classes,
structs, and interfaces, and means that other parts may be defined within the same namespace.

Example: Partial class

public partial class PartialExample


{
// Empty partial class
}

Full Example: Partial class

using static System.Console;

public partial class Employee


{
public string Name { get; set; }
}

public partial class Employee


{
public void WelcomeMessage(string name)
{
WriteLine($"{name}, welcome to our employee information center");
}
}

class ExampleClassInheritance
{
static void Main(string[] args)
{
Employee Employee1 = new Employee();
Employee1.Name = "John";
Employee1.WelcomeMessage(Employee1.Name);
// Output: John, welcome to our employee information center

ReadLine();
}
}

While you can split up larger classes into partial classes, in most cases creating new classes with
more specific sections is advised. Partial classes are generally used for situations that involve “owner”
boundaries, such as with a GUI (Graphical User Interface). The GUI has a framework associated with it
with it and using partial classes will ensure that the framework does not overwrite any of your code.
P a g e | 58

ACCESS MODIFIER: PUBLIC, PROTECTED, AND PRIVATE

Access modifiers control how information can be accessed.

• Public: Can be accessed by any other code in the same assembly or another assembly that
references it.
• Protected: Can be accessed only by the code in the same class or in a class that is derived from
that class.
• Private: Can be accessed only by code in the same class.

Full Example: Public, protected, and private

using static System.Console;

public class VehicleOption


{
public int a = 1;
protected int b = 2;
private int c = 3;
}

class AdvancedOption: VehicleOption


{
static void Main(string[] args)
{
VehicleOption car = new VehicleOption();
car.a = 4; // Able to access data
car.b - 5; // Error: b can only be accessed by classes derived from VehicleOption
// or within the class.
car.c = 6; // Error: c can only be accessed from within the class

AdvancedOption truck = new AdvancedOption ();


truck.a = 7; // Able to access data
truck.b = 8; // Able to access data - B is derived from VehicleOption
truck.c = 9; // Error because private can only be accessed from within the class

ReadLine();
}
}
P a g e | 59

MEMORY: HEAP AND STACK

When a variable is declared, a portion of memory is allocated in RAM. This portion of memory
contains the name, data type, and value of the variable. Depending on the data type, the portion of
memory allocated will be either stack or heap memory.

The stack is used to keep track of local variables and the program’s state. The heap is used to
store data that can be accessed anytime and from anywhere in your program.

Data types are either value types or reference types. The most common reference types are:
strings, arrays, and objects which are on the heap; everything else is a value type on the stack.

Data Types

Stack Heap
Value Types Reference Types

Enumerated Struct String Array Object

Simple

Numeric Bool

Reference types can be assigned a null reference, meaning a reference can point to nothing at
all. This is accomplished using the “null” keyword. Assigning null to value types is not allowed.
P a g e | 60

Full Example: Memory – stack and heap

using static System.Console;

public class MyClass


{
public int g { get; set; }
}

class StackAndHeapExamples
{
static void Main(string[] args)
{
int a = 7; // Value type, Stack
int b = a; // Value type, Stack
bool c = true; // Value type, Stack

string d = "Hello"; // Reference type, Heap


int[] e = new int[20]; // Reference type, Heap

// Instantiates an object: Reference type, Heap


MyClass theObject = new MyClass();
MyClass theSecondObject = theObject;

// Objects: Reference type, Heap


theObject.g = 5;
theSecondObject.g = 9;

// Changing theSecondObject to 9 changed both objects to 9 because it is a reference.


WriteLine(theObject.g); // Output: 9
WriteLine(theSecondObject.g); // Output: 9
}
}
P a g e | 61

MEMORY: BOXING VS UNBOXING

When data moves from value type to a reference type, it is called boxing, and going from
reference type to value type is called unboxing.

Example: Boxing

int a = 123; // Value type


object b = a; // Boxing: Value type to a Reference type

Stack Heap

int a = 123 int 123

object b = a object O 123

Example: Unboxing

int a = 123; // Value type


object b = a; // Boxing: Value type to a reference type
int c = (int)b; // Unboxing: Reference type to value type

Stack Heap

int a = 123 int 123

object b = a object O 123

int c = (int)b int 123


P a g e | 62

STRUCTS

A struct is similar to a class and is useful for lightweight objects, such as point, rectangle, and
color. Lightweight objects can also be created with classes, however it is often more memory efficient to
use a struct. Unlike classes, structs are value types and not reference types like classes.

Example: Struct

public struct TheLocation


{
// Empty struct
}

Full Example: Struct

using static System.Console;

public struct TheLocation


{
public int X { get; private set; }
public int Y { get; private set; }

public TheLocation(int point1, int point2)


{
X = point1;
Y = point2;
}
}

class ExampleStruct
{
static void Main(string[] args)
{
TheLocation theLocation1 = new TheLocation();
WriteLine($"Location1: x = {theLocation1.X}, y = {theLocation1.Y}");
// Output: Location1: x = 0, y = 0

TheLocation theLocation2 = new TheLocation(23, 6);


WriteLine($"Location2: x = {theLocation2.X}, y = {theLocation2.Y}");
// Output: Location2: x = 23, y = 6

ReadLine();
}
}
P a g e | 63

A struct can be declared without using the keyword new. This is unique to structs and this would
not work if it was a class. All value types (Int, Char, Bool, etc.) are structs, which is how you can declare
them without using the keyword “new”.

Full Example: Declaring a struct without using the keyword “new”

using static System.Console;

public struct TheLocation


{
public int X;
public int Y;

public TheLocation(int point1, int point2)


{
X = point1;
Y = point2;
}
}

class ExampleStructWithoutNew
{
static void Main(string[] args)
{
// Previous way
// TheLocation theLocation2 = new TheLocation(23, 6);

TheLocation theLocation3;
theLocation3.X = 23;
theLocation3.Y = 6;

WriteLine($"Location1: x = {theLocation3.X}, y = {theLocation3.Y}");

ReadLine();
}
}
P a g e | 64

NAMESPACES & USING DIRECTIVE

A namespace helps organize a large group of related code. To use a namespace, call it with the
using directive or include it before the class name.

Example: Namespace

namespace NamespaceExampleConsole
{
// empty Namespace
}

The example below uses the “System” namespace. Within the System namespace there is a
class called Console, and within the Console class there is the method WriteLine.

Full Example: Namespace

using System;

class ExampleNamespace
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");

// If “using System;” was not used, the fully qualified name must be used
System.Console.WriteLine("Hello World!");
}
}

The static members of a static class can be accessed without having to specify the type name,
meaning “Console.WriteLine()” can be simplified to just “WriteLine()”. This is done with the “using
static” directive.

Full Example: Using static directive: “System.Console”

using static System.Console;

class ExampleNamespace
{
static void Main(string[] args)
{
WriteLine("Console.WriteLine() is simplified to just WriteLine()");
ReadLine(); // Console.Readline() is simplified to just ReadLine();
}
}
P a g e | 65

Full Example: Namespace created and called

using static System.Console;

namespace Automobiles
{
static class Cars
{
public static string theCar = "ToyotaCar"; // Car info
}

class Trucks
{
// Empty class to demonstrate namespaces can contain multiple classes
}
}

class ANamespaceExample
{
static void Main(string[] args)
{
WriteLine(Automobiles.Cars.theCar);
ReadLine();
}
}

In the example above, within WriteLine “Automobiles.Cars.theCar” the full name had to be
used. However, if the static class directive is used for “Automobiles.Cars”, this can now be shortened to
just “theCar” as demonstrated in the example below.

Full Example: Creating and using a static directive

using static System.Console;


using static Automobiles.Cars;

namespace Automobiles
{
static class Cars
{
public static string theCar = "Toyota Car"; // Car info
}
}

class ANamespaceExample
{
static void Main(string[] args)
{
WriteLine(theCar);
ReadLine();
}
}
P a g e | 66

GENERICS

Generics define type-safe classes without committing to any specific data types. They are
essentially a placeholder until a specified data type is declared. There are a lot of prebuilt classes using
generics. This section covers how to create generic classes. The next section, “List”, demonstrates how
to use a prebuilt generic class.

The example below demonstrates the use of the generic type parameter, which uses the angle
brackets “<>”. Generic type names are usually a single capital letter, “T” being the most common, or a
simple name starting with “T” such as “TKey” or “TValue”.

Example: Generic class

class AGenericClass<T>
{
// Empty generic class
}

Assume in the next example it is being instantiated with a string in the following way:

AGenericClass<string> stringExample = new AGenericClass <string>("Hello");

Example: Generic class

class AGenericClass<T>
{
private T aVariable;

public AGenericClass(T aValue)


{
aVariable = aValue;
WriteLine($"The value is {aVariable} and is a {typeof(T).ToString()}");
// Output: The value is Hello and is a System.String
}

public void DisplayTypeOnly(T aValue)


{
WriteLine($"A {typeof(T).ToString()}"); // Output: A System.String
}
}

In the example above, the generic type parameter “T” uses string as the data type as that is how
the class was instantiated. If the class was instantiated with the data type int then all the corresponding
parameters would have used int instead.
P a g e | 67

Full Example: Generics

using static System.Console;

class AGenericClass<T>
{
private T aVariable;

public AGenericClass(T aValue)


{
aVariable = aValue;
WriteLine($"The value is {aVariable} and is a {typeof(T).ToString()}");
}

public void DisplayTypeOnly(T aValue)


{
WriteLine($"A {typeof(T).ToString()}");
}
}

class ExampleGenericClass
{
static void Main(string[] args)
{
AGenericClass<int> intExample = new AGenericClass<int>(5);
// Output: The value is 5 and is a System.Int32

AGenericClass<string> stringExample = new AGenericClass<string>("Hello");


// Output: The value is Hello and is a System.String

AGenericClass<double> doubleExample = new AGenericClass<double>(5.5);


// Output: The value is 5.5 and is a System.Double

intExample.DisplayTypeOnly(5); // Output: A System.Int32


stringExample.DisplayTypeOnly("Hello"); // Output: A System.String
doubleExample.DisplayTypeOnly(5.5); // Output: A System.Double

ReadLine();
}
}
P a g e | 68

LIST

Lists and arrays are similar in that they both hold items. In general, lists are used more often,
because they can easily search, sort, add, and remove items because of built-in functionalities. Lists can
constantly be changed to include more or fewer items, unlike an array that has a set number of items.

To use a list, add the following line of code below “using System”:

using System.Collections.Generic;

The code above gives access to the Generic namespace which includes the generic List class.
Because the example is using generics, specify the data type of the List class, such as string, int, or
double.

Example: Instantiate an empty list

List<string> foods = new List<string>();

Example: Assign items to a list

List<string> foods = new List<string>();


foods.Add("Pizza");
foods.Add("Burger");

Example: Instantiate and assign items

List<string> foods = new List<string>() {"Pizza", "Burger"};

Example: Insert at a specific index

foods.Insert(5, "Cake");
// Pushes back all items after index 5, items in front of 5 stay the same.

Example: Remove items from a list

foods.Remove("Pizza");
P a g e | 69

Example: Remove at a specific index

foods.RemoveAt(5);

Example: Output an item

WriteLine(foods[0]);

Example: Loop through a list

foreach (var food in foods)


{
WriteLine(food);
}

Example: Get the size of a list

WriteLine(foods.Count);

Example: Sort a list alphabetically and numerically

foods.Sort();

Example: Remove all items from a list.

foods.Clear();

Example: Convert a list to an array

string[] foodsArray = foods.ToArray();


P a g e | 70

Full Example: List

using System.Collections.Generic;
using static System.Console;

class ExampleList
{
static void Main()
{
// Instantiate and assign items to a list
List<string> foods = new List<string>()
{
"Pizza",
"Burger",
"Hot Dog"
};

WriteLine(foods[1]); // Output: Burger

// Loop through entire list and output each item


foreach (var food in foods)
{
WriteLine(food);
// Output: Pizza
// Output: Burger
// Output: Hot Dog
}
ReadLine();
}
}
P a g e | 71

LINKEDLIST

A LinkedList is generally slower than a regular list, however it can be beneficial when
adding/removing items in the middle of a list. As with lists, a LinkedList also uses generics.

To use a LinkedList, add the following line of code below “using System”:

using System.Collections.Generic;

Example: LinkedList

LinkedList<string> ingredientsOrder = new LinkedList<string>();

Full Example: LinkedList and LinkedListNode

using System.Collections.Generic;
using static System.Console;

class ExampleLinkedList
{
static void Main(string[] args)
{
LinkedList<string> ingredientsOrder = new LinkedList<string>();

ingredientsOrder.AddLast("Add an egg");
ingredientsOrder.AddLast("Add butter");
ingredientsOrder.AddFirst("Get a bowl");

// Find the positions of “Get a bowl”


LinkedListNode<string> node = ingredientsOrder.Find("Step1: Get a bowl");
ingredientsOrder.AddAfter(node, "Step2: Add sugar");

foreach (string item in ingredientsOrder)


{
WriteLine(item);
// Output: Get a bowl
// Output: Add sugar
// Output: Add an egg
// Output: Add butter
}
ReadLine();
}
}
P a g e | 72

DICTIONARY

A dictionary consists of a key and a value. In an array, the key is created automatically (0, 1, …);
with dictionaries the key name can be set to something meaningful. As with lists, dictionaries also use
generics.

To use a dictionary, add the following line of code below “using System”:

using System.Collections.Generic;

Dictionaries have two generic data types parameters. Because they are generic, any data type
can be entered. In the example below, the first generic data type is a string and is used as the key. The
second generic data type is an int and is used for the value.

Example: Instantiate a dictionary

Dictionary<string, int> myInventory = new Dictionary<string, int>();

Example: Assign items to a dictionary

Dictionary<string, int> myInventory = new Dictionary<string, int>();


myInventory.Add("Pens", 7);
myInventory.Add("Computers", 2);

Example: Instantiate and assign items to a dictionary

Dictionary<string, int> myInventory = new Dictionary<string, int>


{
{ "Pens", 7 },
{ "Computers", 2 }
};

Example: Remove items from a dictionary

myInventory.Remove("Pens");
P a g e | 73

Example: Update an item

myInventory["Computers"] = 6;

Example: Output an item

WriteLine($"Key: {myInventory["Computers"]}");

To loop through a dictionary, use a ForEach loop and the keyword “KeyValuePair<TKey,
TValue>”. This is needed because dictionary elements are retrieved as KeyValuePair objects.

Example: Loop through a dictionary

foreach (KeyValuePair<string, int> theItem in myInventory)


{
WriteLine($"{theItem.Key}: quantity {theItem.Value} ");
}

Example: Get the size of a dictionary

WriteLine(myInventory.Count);

Example: Remove all items from a dictionary

myInventory.Clear();
P a g e | 74

Full Example: Dictionary

using System.Collections.Generic;
using static System.Console;

class ExampleDictionary
{
static void Main()
{
Dictionary<string, int> myInventory = new Dictionary<string, int>
{
{ "Pens", 7 },
{ "Computers", 2 }
};

WriteLine(myInventory["Pens"]); // Output: 7

// Loop through entire dictionary and output items


foreach (KeyValuePair<string, int> theItem in myInventory)
WriteLine($"{theItem.Key}: quantity {theItem.Value} ");
// Output: Pens: quantity 7
// Output: Computers: quantity 2

ReadLine();
}
}
P a g e | 75

ENUMERATION

An enum (enumeration) is a new value type that consists of a collection of named constants.
Using enums creates a modular design that enhances clarity and reduces the probability of invalid
constants. Enums are generally defined directly in the namespace (outside of any class).

Example: Declare an enum

enum Direction { North, East, South, West };

Example: Assign PlayerDirection an enum value

Direction PlayerDirection = Direction.North;

Example: Output enum value

Direction PlayerDirection = Direction.North;


WriteLine(PlayerDirection); // Output North

Example: Enum value in an If statement

if (PlayerDirection == Direction.North)
WriteLine("The player heads north");
else if (PlayerDirection == Direction.East)
WriteLine("The player heads east into the wood.");

Example: Enum in a ForEach loop

foreach (Direction theEnumItem in Enum.GetValues(typeof(Direction)))


{
WriteLine(theEnumItem);
}
P a g e | 76

Full Example: Enum

using System;
using static System.Console;

namespace EnumExample
{
enum Direction { North, East, South, West };

class EnumExample
{
static void Main(string[] args)
{
Direction PlayerDirection = Direction.North;

Write("You can go the following directions: ");


foreach (Direction theEnumItem in Enum.GetValues(typeof(Direction)))
Write($"{theEnumItem} "); // Output: North East South West

if (PlayerDirection == Direction.North)
WriteLine("The player heads north");
else if (PlayerDirection == Direction.East)
WriteLine("The player heads east into the wood.");

ReadLine();
}
}
}

By default, enum values start at 0. However, numbers can be assigned to enum values.

Full Example: Assign enum numbers

using static System.Console;


namespace EnumAssignNumbersExample
{
enum Months { January = 1, February = 2, March = 3, April = 4, May = 5 }; // and so on..

class EnumExample
{
static void Main(string[] args)
{
Months value = Months.February;
int monthNumber = (int)value;
WriteLine(monthNumber); // Output: 2

ReadLine();
}
}
}
P a g e | 77

TERNARY OPERATOR

The ternary operator tests a condition by comparing two values and returns a third value based
on the results. A ternary operator can often simplify a traditional “If-Else” statement.

Ternary Format:

Condition ? First_Result : Second_Result

Example: Ternary operator

string morningOrNight = (2 < 12) ? "Morning" : "Night"; // Morning is assigned

The example below demonstrates how the ternary operator can be used to get the same result
with less coding.

Example: “If-Else” statement vs ternary operator

int myAge = 23;

// If-Else statement example


string theResponse;
if (myAge < 21)
theResponse = "Under 21 years old";
else
theResponse = "Over 21 years old";

WriteLine(theResponse); // Output: Over 21 years old

// Ternary operator example


string theResponse2 = (myAge < 21) ? "Under 21 years old" : "Over 21 years old";

WriteLine(theResponse2); // Output: Over 21 years old


P a g e | 78

Full Example: Ternary operator in a method

using static System.Console;

class TernaryInAMethodExample
{

public static string AgeCheck(int theAge)


{
return (theAge < 21) ? "Under 21 years old" : "Over 21 years old";
}

static void Main(string[] args)


{
WriteLine(AgeCheck(19)); // Output: “Under 21 years old”
}
}
P a g e | 79

RANDOM NUMBER

It is often necessary to create a random number in software applications. Below are several
techniques on how to create a random number using the Random class.

Example: Random number from 0 to 2,147,483,646

Random r = new Random(); // Instantiate object r from the Random class

// The Next() method within the r object returns a number from 0 to Int32.MaxValue
int myRandomNumber = r.Next();

Example: Argument in Next method – “maxValue”

Random r = new Random(); // Instantiate object r from the Random class

// The Next method will return a non-negative random integer that is less than the
// specified maximum value supplied.
int myRandomNumber = r.Next(11); // Output: Will vary from 0 to 10

Example: Arguments in Next Method - “minValue” and “maxValue”

Random r = new Random(); // Instantiate object r from the Random class

int myRandomNumber = r.Next(10, 21); // (minValue, maxValue)


// minValue is greater than or equal to.
// maxValue is less than the specified maximum.
// Output: Will vary from 10 to 20

Full Example: Random number in a method

using System;
class RandomNumberExample
{
private static Random r = new Random(); // Instantiate object r from the Random class
public static int RandomNumMethod(int num1)
{
return r.Next(1, num1);
}

static void Main(string[] args)


{
Console.WriteLine(RandomNumMethod(5001)); // Output: Will vary from 1 to 5000
Console.ReadLine();
}
}
P a g e | 80

THIS (REFERENCE)

The “this” keyword refers to the current instance of the class; it helps to qualify members
hidden by the same name. The “this” keyword can also be used to pass the entire instance of the
current class to a parameter as an object.

Example: this

private string name = "Adam";


public void DisplayName(string name = "David")
{
WriteLine(this.name); // Output: Adam
WriteLine(name); // Output: David
}

Full Example: this

using static System.Console;


class NameClass
{
private string name = "Adam";
public string FirstName { get; set; } = "Samantha";
public string LastName { get; set; } = "West";

public void DisplayName(string name)


{
WriteLine(this.name); // Output: Adam
WriteLine(name); // Output: David
WriteLine(NameHelp.CombineName(this)); // Send entire instance of current class to
// another class
}
}

static class NameHelp


{
public static string CombineName(NameClass name)
{
return $"{name.FirstName} {name.LastName}"; // Output: Samantha West
}
}

class ThisExample
{
static void Main(string[] args)
{
NameClass example1 = new NameClass();
example1.DisplayName("David");
ReadLine();
}
}
P a g e | 81

METHODS: EXTENSION

Extension methods define a method that appears to belong to a class to which it does not in
fact belong. Extension methods must be defined in static classes and be static methods.

The built in string class contains methods such as: “ToLower()” and “Length()”. In the example
below, an extension method called “ToStarBox()” is created and can be used like the previous string
methods mentioned. It will appear to be in the string class, when in fact it is not.

Extension method parameters must start with the keyword “this” followed the type that is being
created, in our example the string data type.

Example: Create extension method

public static class StringExtensionExample


{
public static void ToStarBox(this string text)
{
string starLine = "**";
for (int i = 0; i < text.Length; i++)
starLine += "*";

WriteLine(starLine);
WriteLine($"*{text}*");
WriteLine(starLine);
}
}

Example: Call extension method

string aWord = "Hello";


aWord.ToStarBox();
// Output: *******
// *Hello*
// *******
P a g e | 82

Full Example: Extension Method

using static System.Console;

public static class StringExtensionExample


{
public static void ToStarBox(this string text)
{
string starLine = "**";
for (int i = 0; i < text.Length; i++)
starLine += "*";

WriteLine(starLine);
WriteLine($"*{text}*");
WriteLine(starLine);
}
}

class ExtensionMethodExample
{
static void Main(string[] args)
{
string aWord = "Hello";
aWord.ToStarBox();
// Output: *******
// *Hello*
// *******

ReadLine();
}
}
P a g e | 83

TUPLES

A Tuple can be thought of much like an array, however a Tuple collection can contain different
data types. Tuple classes are generic containers and can hold between 1 to 8 items.

Example: Instantiate a Tuple

Tuple<int, string, int[]> myTuple = Tuple.Create(101, "Hello", new int[] { 41, 52 });

To access the information within a Tuple, use the name of the Tuple and then “.Item1”, “.Item2”
and so on.

Example: Instantiate and access a Tuple

//Instantiate a 3-Item Tuple: Int, String, and an Array of Ints


Tuple<int, string, int[]> myTuple = Tuple.Create(101, "Hello", new int[] { 41, 52 });

// Access a Tuple Item


WriteLine(myTuple.Item1); //Output: 101
WriteLine(myTuple.Item2); //Output: Hello

foreach (int theNumber in myTuple.Item3)


{
Write($"{theNumber} "); //Output 41 52
}

Example: Tuple in a method

public static Tuple <int, int> DivideGetQuotientAndRemainder(int dividend, int divisor)


{
int quotient = dividend / divisor;
int remainder = dividend % divisor; // Gets the remainder

return Tuple.Create(quotient, remainder);


}

static void Main(string[] args)


{
Tuple <int, int> answer = DivideGetQuotientAndRemainder(10, 4);
WriteLine($"{num1} / {num2} = {answer.Item1}, with remainder of {answer.Item2}");
// Output: 10 / 4 = 2, with remainder of 2
}
P a g e | 84

STRINGBUILDER

When the value of a string is changed, a new string object in memory is created. This is because
a string is immutable (meaning cannot be changed once created). This uses additional system resources.
StringBuilder is a mutable string-like object whose value will change based on the sequence of
characters (a new string object in memory is not created when appended).

To use StringBuilder, include the using statement:

using System.Text;

Example: Instantiate a StringBuilder

StringBuilder theBuilder = new StringBuilder("Hello World!");

Example: Append a StringBuilder

StringBuilder theBuilder = new StringBuilder("Hello World!");


theBuilder.Append(" Today is going to be great!");
WriteLine(theBuilder); // Output: "Hello World! Today is going to be great!

Example: Insert a StringBuilder

StringBuilder theBuilder = new StringBuilder("Hello how are you?");


theBuilder.Insert(5, " Jason,");
WriteLine(theBuilder); // Output: "Hello Jason, how are you?

Example: Remove a StringBuilder at a specified index with specified length

StringBuilder theBuilder = new StringBuilder("Hello how are you?");


theBuilder.Remove(5, 13);
WriteLine(theBuilder); // Output: "Hello"
P a g e | 85

Example: Replace part of a StringBuilder

StringBuilder theBuilder = new StringBuilder("Hello, how are you?");


theBuilder.Replace("Hello", "Jason");
WriteLine(theBuilder); // Output: "Jason, how are you?"

Example: Replace the entire string

StringBuilder theBuilder = new StringBuilder("Hello, how are you?");


theBuilder.Replace(theBuilder.ToString(), "Completely new text");
WriteLine(theBuilder); // Output: "Completely new text."

Full Example: StringBuilder

using System.Text;
using static System.Console;

class ExampleStringBuilder
{
static void Main(string[] args)
{
StringBuilder theBuilder = new StringBuilder("Hello World!");

theBuilder.Append(" Today is going to be great!");


WriteLine(theBuilder); // Output: Hello World! Today is going to be great!

theBuilder.Replace("World", "Jason");
WriteLine(theBuilder); // Output: Hello Jason! Today is going to be great!

theBuilder.Replace(theBuilder.ToString(), "Completely new text");


WriteLine(theBuilder); // Output: "Completely new text."

ReadLine();
}
}
P a g e | 86

TRY-CATCH

Try-Catch is used in scenarios that might throw an exception. Exception handling is the name
used for errors in object-oriented programs, meaning if there is an exception within the try section of
code, the program will go directly to the catch block of code. The catch block can specify the type of
exception being looked for. In the example below, this will handle all exceptions.

Example: Try-Catch

try
{
// Code that could potentially cause an exception
}
catch (Exception ex)
{
// Handle the exception
}

Finally can optionally be added to the end of a Try-Catch. The code in the finally statement will
always run. A common use for finally is if a file is open, finally can guarantee that the file will be closed
even if an error occurs.

Example: Finally and multiple catches

try
{
// Code that could potentially cause an exception
}
catch (OverflowException ex)
{
// Handle the exception if it is an OverflowExcpetion
}
catch (Exception ex)
{
// Handle all other exceptions
}
finally
{
// This code will always execute if there is or isn't an exception.
}
P a g e | 87

Full Example: Try-Catch handles an exception if incorrect data is entered, such as: “asdf”

using System;
using static System.Console;

class TryCatchExample
{
static void Main(string[] args)
{
try
{
int theDay;
int theMonth;
int theYear;

WriteLine("Enter a day between 1 to 31");


theDay = int.Parse(ReadLine());

WriteLine("Enter a month between 1 to 12");


theMonth = int.Parse(ReadLine());

WriteLine("Enter a 4-digit year");


theYear = int.Parse(ReadLine());

DateTime dt = new DateTime(theYear, theMonth, theDay);


string displayDate = string.Format("{0:dddd, MMM d, yyyy}", dt);

WriteLine(displayDate);
}
catch (Exception ex)
{
WriteLine($"Exception: {ex.ToString()}");
}
finally
{
// Finally can optionally be added to a Try-Catch.
}
ReadLine();
}
}
P a g e | 88

UNIT TESTING

Unit Tests verify that the logic of code is working as expected. Unit testing breaks down a
program into small, testable, individual units.

Walkthrough: Setting up a .NET Core Console Application xUnit Test

The objective of this program is to build a calculator that adds two numbers. Unit Testing will be
included to validate that the program performs as designed.

1. Create a .NET Core Console Application named UTCalculator.

2. Create a class named “CalculatorFeatures” and add a method called “AddTwoNumbers”.

using System;

namespace UTCalculator
{

public class CalculatorFeatures


{
public static int AddTwoNumbers(int num1, int num2)
{
int result = num1 - num2;
return result;
}
}

class Program
{
static void Main(string[] args)
{
}
}

}
P a g e | 89

3. Add a “WriteLine” and “ReadLine” in the Main method as shown below.

static void Main(string[] args)


{
Console.WriteLine(CalculatorFeatures.AddTwoNumbers(10, 4));
Console.ReadLine();
}

The code above will run, because there are no syntax errors in it. However, there is a logic error
(10 + 4 should equal 14 not 6). A Unit Test will be added to catch this type of error.

4. In Solution Explorer (pictured on the right),


right click on Solution, click on Add, then click New
Project -> Visual C# -> .NET Core -> xUnit Test Project.
Name it “CalculatorTest” and click OK.

The template for a xUnit Test has now been created. Next a reference needs to be added for the
Unit Test to be connected to UTCalculator.

In the Solution Explorer expand CalculatorTest, right click on Dependencies, and click Add
Reference. The Reference Manager will open. On the left menu, click on Projects -> Solution and add a
checkmark next to UTCalculator. Click OK.
P a g e | 90

Make the following modifications to the Project CalculatorTest, UnitTest1.cs file.

First, add the using declaration for UTCalculator:

using UTCalculator; // Needed to access UTCalculator class

Next, modify the method below [Fact] to:

[Fact]
public void TestAddMethodResultShouldBeNine()
{
int result = CalculatorFeatures.AddTwoNumbers(5, 4);
Assert.Equal(9, result);
}

Unit Test names should be self-documenting. In our example the name


“TestAddMethodResultShouldBeNine” describes exactly what it is expected.

Within the test “Assert.Equal(9, result)” is used to compare the expected result with the answer
that the method response returns. When the test is run if 9 matches the result, it will pass the test,
otherwise it will fail.

Full Example: xUnit Test

using Xunit;
using UTCalculator; //ADD this to access UTCalculator class

namespace CalculatorTest
{
public class UnitTest1
{
[Fact]
public void TestAddMethodResultShouldBeNine()
{
int result = CalculatorFeatures.AddTwoNumbers(5, 4);
Assert.Equal(9, result);
}
}
}
P a g e | 91

On the top menu bar select Test -> Run -> All Test. The test will fail. If the Test Explorer did not
come up, select Test -> Windows -> Test Explorer.

Click on the failed test for more information. A message will say “Equal Failed, expected 9 and
Actual was 1”. This indicates a logical error in the “AddTwoNumbers” method.

It is now clear that the numbers are being subtracted: “int result = num1 - num2;”

Change the minus sign to a plus sign: “int result = num1 + num2;”

public class CalculatorFeatures


{
public static int AddTwoNumbers(int num1, int num2)
{
int result = num1 + num2;
return result;
}
}

Run the test again to verify all tests are passed.


P a g e | 92

UNIT TESTING: FACT & THEORY

With xUnit tests, they are either marked with the attribute [Fact] or [Theory]. Fact indicates
a test, and Theory gives the ability to pass multiple data tests to the same unit test using InlineData. In
the previous Unit Test walkthrough, the Assert class was utilized to compare results. The Assert class
contains various methods that return a bool result. In the following examples “Assert.Equal” will be
used.

Below is the class and method with which the xUnit Test will correspond. This is the same code
previously used in the Unit Testing walkthrough.

public class CalculatorFeatures


{
public static int AddTwoNumbers(int num1, int num2)
{
int result = num1 + num2;
return result;
}
}

Example: Fact - Assert.Equal

[Fact]
public void TestAddMethodResultShouldBeNine()
{
int result = CalculatorFeatures.AddTwoNumbers(5, 4);
Assert.Equal(9, result);
}

Example: Theory – Assert.Equal

[Theory]
[InlineData(5, 4, 9)]
[InlineData(6, 1, 7)]
[InlineData(2, 3, 5)]
public void AddTwoNumbersAndGetResult(int firstNum, int secondNum, int expectedResult)
{
int result = CalculatorFeatures.AddTwoNumbers(firstNum, secondNum);
Assert.Equal(expectedResult, result);
}
P a g e | 93

DIRECTIVES

Preprocessor directives are useful in improving readability, reducing complexity, and helping
with maintenance of a program.

Example: #region and #endregion directives

• #region is used to indicate a certain block of code. This will help keep your code organized as
blocks and can be expanded or collapsed in Visual Studio.

#region DisplayPrompts
WriteLine("Hello");
WriteLine("World");
#endregion

Full Example: #define, #if, #else, and #endif

• #define must be in the top of the code.


• The #Else statement in Visual Studio is now grayed out, indicating this section of code will not be
compiled because DevMode is defined.

#define DevMode
using static System.Console;

class ExampleDirectives
{
static void Main(string[] args)
{
string myDatabase = "";
#if (DevMode)
{
WriteLine("In development Mode, using local database");
myDatabase = "C:\\LocalDatabase....";
}
#else
{
WriteLine("In development Mode, using local database");
myDatabase = "C:\\LocalDatabase...."
}
#endif
}
}

Below is a list of preprocessor directives:

Conditional compilation: #if, #else, #elif, #endif, #define, #undef

Other: #warning, #error, #line, #region, #endregion, #pragma, #pragma warning, #pragma checksum
P a g e | 94

WRITING/READING TEXT FILES

Variables are temporary in that once the program is turned off, the data is lost. Writing/Reading
to a text file is a permanent way to handle data that needs to be saved when the program is turned off.

The StreamWriter class writes to text files. This class in contained within “System.IO”
namespace. To use this class, include the following at the top of the page.

using System.IO;

A “using” statement is also used in front of StreamWriter. The using statement removes the
SteamWriter from memory when it is no longer needed.

Full Example: Write to a file; the file will be saved in the folder of your current project

using System;
using System.IO;

class TextFileExample
{
static void Main(string[] args)
{
string fileName = "test.txt";
string textToAdd = "Example text to save";

// true means if this file already exists, append it.


using (StreamWriter writer = new StreamWriter(fileName, true))
{
writer.Write(textToAdd);
}
}
}

The ability to read from this file is also needed, and for that use StreamReader, which is set up
with a very familiar syntax to StreamWriter.

Example: Read from a file, 1 line or whole text file

using (StreamReader reader = new StreamReader(fileName))


{
string onlyOneLine = reader.ReadLine();
string wholeTextfile = reader.ReadToEnd();

WriteLine(wholeTextfile);
}
P a g e | 95

INTERFACES

An interface behaves as a contract between itself and any class where it is used. A class that
implements an interface must now implement all its members. Interfaces can only contain declarations
and all the members are implicitly abstract and public. Interfaces are usually named with a capital “I”,
although it is not required.

Example: Interface

interface IPets
{
void Greeting();
string Name { get; set; }
}

public class Cat : IPets


{
// IPets interface was used on this class, the class must now have a
// Greeting method and a Name property, otherwise there will be an error.
public string Name { get; set; }
public void Greeting()
{
WriteLine($"Hello cat named {Name}");
}
}

There are useful built-in interfaces, such as: IEnumerable, IList, IDictionary, and IComparable.
Adding the interface IEnumerable to a class means it will iterate. The class must also now contain
IEnumerator. In the example below, a class for a deck of cards is created and iterated over.

Full Example: IEnumerable and IEnumerator

using System.Collections;
using System.Collections.Generic;
using static System.Console;

// Set up the properties of a playing card


class Card
{
public string Name { get; set; }
public int Value { get; set; }
public string Suit { get; set; }

public Card(string name, int value, string suit)


{
Name = name;
Value = value;
P a g e | 96

Suit = suit;
}
}

// The class below can be iterated over to display a deck of cards


class DeckOfCards : IEnumerable
{
private List<Card> deckList = new List<Card>();

public DeckOfCards()
{
deckList.Add(new Card("Two", 2, "Spade"));
deckList.Add(new Card("Three", 3, "Spade"));
deckList.Add(new Card("Four", 4, "Spade"));
}

// IEnumerator must be used, because DeckOfCards inherits IEnumerable


public IEnumerator GetEnumerator()
{
return deckList.GetEnumerator();
}
}

class ExampleIEnumerable
{
static void Main(string[] args)
{
DeckOfCards theDeck = new DeckOfCards();

foreach (Card itemCard in theDeck)


WriteLine($"Card: {itemCard.Suit} {itemCard.Name} ({itemCard.Value})");

ReadLine();
}
}

C# does not allow multiple inheritance in classes; however, multiple interfaces are allowed. If
interfaces are added to a class that is also inheriting from a base class, the interfaces must follow the
base class.

Example: Multiple interfaces and base class

public class DeckOfCards : ABaseClass, IInterface, IAnotherInterface


{
// Empty class
}
P a g e | 97

YIELD

Yield return and yield break are used when implementing an iterator (IEnumerable). The yield
return statement returns the next element in the sequence, whereas yield break ends the iteration.

Full Example: Yield return and yield break

using System.Collections.Generic;
using static System.Console;

class ExampleYieldReturnAndBreak
{
public static List<int> MyNumbers = new List<int> { 9, 4, 20, 3, 7, 12 };

public static IEnumerable<int> GreaterThan5StopIf7()


{
foreach (int item in MyNumbers)
{
if (item == 7)
yield break; // End iteration
else if (item > 5)
yield return item; // Return element and continue iteration
}
}

static void Main(string[] args)


{
WriteLine("Output all numbers greater than 5, stop if number is 7");

foreach (int item in GreaterThan5StopIf7())


Write($"{item} "); // Output: 9 20

ReadLine();
}
}
P a g e | 98

DELEGATES

Delegates are a variable that can store a method and can then be passed around as needed.
Previously the variables discussed held data such as strings or objects, however methods can be treated
the same way. In the example below, a delegate named “MathExample” can store methods that accept
two integer values and return a string value.

Example: Create a delegate

public delegate string MathExample(int num1, int num2);

Full Example: Use a delegate

MathExample calculateMath = AddNumbers; // Store method AddNumbers

Full Example: delegate

using static System.Console;

class DelegateExample
{
public delegate string MathExample(int num1, int num2);

public static string AddNumbers(int a, int b)


{
string message = $"{a} + {b} = {a + b}";
return message;
}

static void Main(string[] args)


{
int number1 = 3;
int number2 = 7;

MathExample calculateMath = AddNumbers; // Store method AddNumbers


WriteLine(calculateMath(number1, number2)); // Output: 10

ReadLine();
}
}
P a g e | 99

Example: Declare and instantiate an array of delegates

MathExample[] mathOperations = { AddNumbers, MultiplyNumbers };

Full Example: Array of delegates

using static System.Console;

class DelegateExample
{
public delegate string MathExample(int num1, int num2);

public static string AddNumbers(int a, int b)


{
string message = $"{a} + {b} = {a + b}";
return message;
}

public static string MultiplyNumbers(int a, int b)


{
string message = $"{a} * {b} = {a * b}";
return message;
}

static void Main(string[] args)


{
int number1 = 3;
int number2 = 7;

// Declare and instantiate an array of MathExample


MathExample[] mathOperations = { AddNumbers, MultiplyNumbers };

foreach (var mathOperation in mathOperations)


WriteLine(mathOperation(number1, number2));
// Output: 3 + 7 = 10
// Output: 3 * 7 = 21

ReadLine();
}
}
P a g e | 100

EVENTS

Events allow classes to notify other classes when something occurs. GUI (Graphical User
Interfaces) applications often use Events to indicate when something occurs. One GUI example is when a
button is pressed and other classes are listening to handle that event.

There are multiple components to an event. Each of the examples below cover one of these
components. Following all the examples is a full example that has all the components put together.

An event needs to be defined inside a class. Using the “event” keyword enables others to attach
to this event. Specify the delegate type for the type of methods that can be attached to the event. In the
example below, a predefined delegate called “EventHandler” is used. The EventHandler delegate returns
void and has two parameters (object, EventArgs). Object is the sender (what sent the event) and
EventArgs object (contains basic information about the event).

Example: Define an event

public event EventHandler WelcomeChanged; // Define the event

The code below verifies that an event handler is attached to an event. Methods that raise events
typically start with the word “On”.

Example: Raise an event

public void OnWelcomeChanged()


{
WelcomeChanged?.Invoke(this, EventArgs.Empty);
}
P a g e | 101

In the example below, when “TheMessage” value is set, then it will call the method
“OnWelcomeChanged” to raise the event.

Example: Call method to raise an event

private string theMessage;


public string TheMessage
{
get { return theMessage; }
set {
theMessage = $"Hello, {value}";
OnWelcomeChanged(); // Call OnWelcomeChanged when the value is changed
}
}

The method below handles what to do when the change is detected. This method needs to be
setup based on the delegate used, in this case the “EventHandler” delegate.

Example: Handle the event

public void HandleWelcomeChanged(object sender, EventArgs eventArgs)


{
WriteLine("The welcome message has changed!!");
}

Below is how to attach an event handler to an event; the “+=” operator is used to accomplish
this. You can attach multiple event handlers to an event if needed.

Example: Attach event handler to an event

welcomeMessage.WelcomeChanged += welcomeMessage.HandleWelcomeChanged;
P a g e | 102

Full Example: Event

using System;
using static System.Console;

class Greetings
{
private string theMessage;
public string TheMessage
{
get { return theMessage; }
set
{
theMessage = $"Hello, {value}";
OnWelcomeChanged(); // Call OnWelcomeChanged when the value is changed
}
}

public event EventHandler WelcomeChanged; // Define the event


// EventHandler is a predefined delegate that returns void and has 2 parameters.
// The first parameter is an object and the second is an EventArgs object

public void OnWelcomeChanged() // Methods that raise events usually start with the "On"
{
// The code below raises the event if the event is not null (verifies an event handler
// is attached to the event)
WelcomeChanged?.Invoke(this, EventArgs.Empty);
}

// This method handles what to do when the change is detected


public void HandleWelcomeChanged(object sender, EventArgs eventArgs)
{
WriteLine("The welcome message has changed!!");
}
}

class EventExample
{
static void Main(string[] args)
{
Greetings welcomeMessage = new Greetings();

// Attach event handler to event


welcomeMessage.WelcomeChanged += welcomeMessage.HandleWelcomeChanged;

welcomeMessage.TheMessage = "Adam";
WriteLine(welcomeMessage.TheMessage);

ReadLine();
}
}
P a g e | 103

LAMBDAS

A lambda is essentially a method without a declaration; it uses a clear and short syntax. Write a
shorthand method directly in the place it is intended to be used. This is especially useful on small
methods that are used only once. The lambda operator is “=>” and can be read as “goes to”. The lambda
operator separates the expression into two parts (left side parameter, right side lambda body).

Example: Lambda

ANewNumber addFive = x => x + 5;

Full Example: Lambda using a delegate

using static System.Console;


class LambdaExample
{
delegate int ANewNumber(int input);

static void Main(string[] args)


{
ANewNumber addFive = x => x + 5;
WriteLine(addFive(2)); // Output: "7"
ReadLine();
}
}

Full Example: Lambdas and lists

using System.Collections.Generic;
using static System.Console;

class LambdaExample
{
static void Main(string[] args)
{
List<int> list = new List<int>() { 5, 3, 4, 5, 6, 7 };

// Gets all 5's from list


List<int> numberFives = list.FindAll(x => x == 5);
WriteLine($"There are {numberFives.Count} 5's in the list");

// Gets all odd numbers from list


List<int> oddNumbers = list.FindAll(x => (x % 2) != 0);
WriteLine($"There are {oddNumbers.Count} ODD numbers:");
ReadLine();
}
}
P a g e | 104

The lambda expression syntax can also be used on various expression-bodied members that are
a single expression. In the example below, a single expression method is simplified using the lambda
expression syntax.

Full Example: Expression-bodied members with lambda expression syntax

using static System.Console;

class ExpressionBodiedExample
{
// “Regular” Method
public static int SquareNumber1(int number)
{
return number * number;
}

// Same method but using lambda expression syntax


public static int SquareNumber2(int number) => number * number;

static void Main(string[] args)


{
WriteLine(SquareNumber1(5)); // Output: 25
WriteLine(SquareNumber2(5)); // Output: 25

ReadLine();
}
}
P a g e | 105

THREADS

Threads add the functionality of running multiple sections of code simultaneously. Threading
allows the code to run on multiple processors. This provides a performance boost.

To use threads, include the following at the top of the page.

using System.Threading;

The “Thread” class constructor used below contains a delegate that accepts methods that return
void; only methods that return void can be used.

Example: Create a thread object

Thread aThread = new Thread(CountTo50);

In the example below, the “Start” method is used and it can accept zero or one parameter.

Example: Start a thread

aThread.Start(); // No parameters
bThread.Start(50); // 1 parameter

Full Example: Thread – No parameters

using System.Threading;
using static System.Console;

class ThreadExample
{
public static void CountTo50()
{
for (int i = 1; i <= 50; i++)
WriteLine(i);
}

static void Main(string[] args)


{
Thread aThread = new Thread(CountTo50);
aThread.Start();

ReadLine();
}
}
P a g e | 106

The previous example uses the “Start” method to create a new thread that will begin executing
the method “CountTo50”. At this point the two threads are now running simultaneously, the original
thread and now the new “aThread” as well.

In the example below, the “Join” method instructs the original thread to wait until “aThread”
has completed. The original thread will be “frozen” until it finishes, essentially joining the two threads.

Example: Join

aThread.Join();

Full Example: Join

using System.Threading;
using static System.Console;

class ThreadExample
{
public static void CountTo50()
{
for (int i = 1; i <= 50; i++)
WriteLine(i);
}

static void Main(string[] args)


{
Thread aThread = new Thread(CountTo50);
aThread.Start();

Thread bThread = new Thread(CountTo50);


bThread.Start();

aThread.Join(); // wait until aThread is finished


bThread.Join(); // wait until bThread is finished
ReadLine();
}
}

When the example above is run, the results will not output in sequence 1-200 each time. Both
threads are running at the same time and will each output their numbers as their thread is being run.
For example, the results might be 1-70 and then the other thread could output 1-50, then the first
thread could output 71-120 and so on.
P a g e | 107

The example below demonstrates using a parameter in the “Start” method. It is important to
note that the method parameter must be an object. The object can later be cast. In the example below,
it is cast from an object to an int.

Full Example: Thread – One parameter

using System.Threading;
using static System.Console;

class ThreadExample
{
public static void CountTo(object count)
{
for (int i = 1; i <= (int)count; i++)
WriteLine(i);
}

static void Main(string[] args)


{
Thread aThread = new Thread(CountTo);
aThread.Start(50); // 1 parameter

ReadLine();
}
}
P a g e | 108

ASYNCHRONOUS

Asynchronous programming helps enhance the responsiveness of applications by using non-


blocking operations to prevent bottlenecks that could slow down or freeze an application. The two main
components to asynchronous programming are the keyword modifiers async and await.

A method using the async modifier enables the use of the await operator, which now must be
included at least once within the method. When the await operator is reached, the original caller
method will continue and the async method will continue to process until it is completed.

Async methods must have a return type of void, Task, Task<T>, or any other type that has a
GetAwaiter method. The naming convention for async methods is to append them with an “Async”
suffix.

Full Example: Async void method

using static System.Console;


using System.Threading.Tasks; // Needed for the Task.Delay functionality

class ExampleAsync
{
static void Main(string[] args)
{
FirstMethodAsync();
WriteLine("System is not Frozen");
ReadLine();
}

static async void FirstMethodAsync()


{
WriteLine("Task Started");
await Task.Delay(3000); // Delays the method for 3 seconds
WriteLine("Task Finished");
}
// Output: "Task Started"
// "System is not Frozen"
// "Task Finished"
}

In the example above, the method “FirstMethodAsync()” contains a delay that would generally
“freeze” a program for 3 seconds. Because this is an async method, when await is reached the original
caller of the method will continue and the async method will keep processing.
P a g e | 109

Async methods can return with void as demonstrated previously, however they generally return
with Task or Task<TResult>, which encapsulate information. Task is used if there is no return statement,
and Task<TResult> is used if there is a return statement.

To use tasks, include the following at the top of the page:

using System.Threading.Tasks;

When the task return type is used instead of void, the method call can now use the await.

Example: Await method

await SecondMethodAsync();

Full Example: Async Task method

using static System.Console;


using System.Threading.Tasks;

class ExampleAsync
{
static void Main(string[] args)
{
FirstMethodAsync();
WriteLine("System is not Frozen");
ReadLine();
}

static async void FirstMethodAsync()


{
WriteLine("Task Started");
await SecondMethodAsync();
WriteLine("First Task Finished");
}

static async Task SecondMethodAsync()


{
await Task.Delay(3000); // Delays the method for 3 seconds
WriteLine("Second Task Finished");
}
// Output: Task Started
// System is not Frozen
// Second Task Finished
// First Task Finished
}
P a g e | 110

Full Example: Async Task<TResult> method

using static System.Console;


using System.Threading.Tasks;

class ExampleAsync
{
static void Main(string[] args)
{
FirstMethodAsync();
WriteLine("System is not Frozen");
ReadLine();
}

static async void FirstMethodAsync()


{
WriteLine("Task Started");
WriteLine(await SecondMethodAsync());
WriteLine("First Task Finished");
}

static async Task<string> SecondMethodAsync()


{
await Task.Delay(3000); // Delays the method for 3 seconds
return ("Second Task Finished");
}
// Output: Task Started
// System is not Frozen
// Second Task Finished
// First Task Finished
}

It is very common to see async programming on graphical applications. For example, if a button
is pressed and content from the internet needs to be downloaded, the whole program should not be
frozen while it downloads. The program should download the content in the background while the user
is still able to use the application.
P a g e | 111

QUERY EXPRESSIONS: LINQ – QUERY SYNTAX

A query expression statement extracts specific information from a collection of data. The query
syntax in C# is called “Language Integrated Query”, commonly referred to by its shortened name,
“LINQ”.

LINQ queries are used on collections of data, such as Lists or Arrays, which are container types
for the “IEnumerable<T>” interface. Any container type of “IEnumerable<T>” can use a LINQ query.

To use a LINQ query, add the following line of code below “using System”:

using System.Linq;

In the examples below, the various clauses that make up a query are covered. Clauses are a
smaller syntax than a full expression; LINQ queries require multiple clauses to be a complete expression.

Queries always start with a “from” clause. The from clause defines a source of information for
the query and a range variable. A range variable is a local variable that is available throughout the query,
like the variable in a “ForEach” loop.

Example: “From” clause

from o in students

The select clause specifies the part or whole object to be used for the results of the query
expression. The example below demonstrates selecting the entire object.

Example: “Select” clause

select o;

The results from a LINQ query are always output as “IEnumerable<T>” and can be converted to
a list or array if needed using “ToList()” or “ToArray()” .

Example: Full expression - assign results to a variable

IEnumerable<StudentInfo> aStudents = from o in students


select o;
P a g e | 112

Queries can be created using only “from” and “select” clauses; the “where” clause specifies
which items to use.

Example: “Where” clause

where o.Grade > 90

Example: Full expression using “where” clause

IEnumerable<StudentInfo> aStudents = from o in students


where o.Grade > 90
select o;

The example below uses the “let” clause which creates derived range variables. A derived range
variable uses the range variable created in the “from” clause. “Let” clauses define a variable to use in
multiple places in the query or to simplify a complex operation. In the example below, “select” also
selects a string instead of an object, and IEnumerable is modified to reflect this change.

Example: Full expression using “let” clause

IEnumerable<string> studentAverages = from o in students


let averageGrade = (o.Grade1 + o.Grade2) / 2
select $"{o.Name} grade average: {averageGrade}";

A “join” clause combines two collections together based on a condition. In the example below,
the collections are joined together when the “StudentID” values are equal in both collections. The left
side of the equals must reference an earlier ranger variable and the right side references a new range
variable; this is called an inner join.

Example: Full expression using “join” clause

var inUseBooks = from o in students


join b in books on o.StudentID equals b.StudentID // Inner join
select new { o.Name, b.BookName }; // New collection using these types
P a g e | 113

The “OrderBy” clause sorts all items in a collection. The default is ascending, however they can
also be specified for descending.

Example: “OrderBy” clause

orderby o.Name // Ascending by default


orderby o.Name descending // Descending example
orderby o.Name, o.StudentID descending // Multilevel sort: Sort by name then StudentID

Example: Full expression using “OrderBy” clause

IEnumerable<StudentInfo> aStudents = from o in students


orderby o.Name // Ascending by default
select o;

The “group” clause bundles elements into groups based on the information specified. In the
example below, the books collection will have a group for each “BookName”. Previously the “select”
clause has been needed to finish a full expression, however the “group” clause is the other way to finish
a full expression.

Example: Full expression using “group” clause

var bookGroups = from o in books


group o by o.BookName;

In the example above, “var” is representing the syntax “IEnumerable<IGrouping<TKey,


TElement>>”. “TKey” in this case is going to be a string for the book name and “TElement” is the class
from which the collection was made.
P a g e | 114

Full Example: Query Expressions

using System.Collections.Generic;
using System.Linq;
using static System.Console;

class StudentInfo
{
public int StudentID { get; set; }
public string Name { get; set; }
public int Grade1 { get; set; }
public int Grade2 { get; set; }
}

class BookInfo
{
public int StudentID { get; set; } = 0;
public string BookName { get; set; }
}

class QueryExample
{
static void Main(string[] args)
{
// Lists, students, and books will be used as our collections for this example
List<StudentInfo> students = new List<StudentInfo>
{
new StudentInfo {StudentID = 1, Name = "Jonathan", Grade1 = 95, Grade2 = 90},
new StudentInfo {StudentID = 2, Name = "Maria", Grade1 = 92, Grade2 = 85},
new StudentInfo {StudentID = 3, Name = "Marcos", Grade1 = 81, Grade2 = 91}
};

List<BookInfo> books = new List<BookInfo>


{
new BookInfo {StudentID = 1, BookName = "C# Fundamentals"},
new BookInfo {StudentID = 1, BookName = "Microsoft Magazine"},
new BookInfo {StudentID = 2, BookName = "C# Fundamentals"}
};

// Minimal query expression


IEnumerable<StudentInfo> students1 = from o in students
select o;

// Where specifies which items to use, in this example all Grade1 greater than 90
IEnumerable<StudentInfo> students2 = from o in students
where o.Grade1 > 90
select o;

// Display grades greater than 90


foreach (var student in students2)
WriteLine($"Name: {student.Name} Grade: {student.Grade1}");
// Output: Name: Jonathan Grade: 95
// Name: Maria Grade: 92
P a g e | 115

// Let creates derived range variables


IEnumerable<string> studentAverages = from o in students
let averageGrade = (o.Grade1 + o.Grade2) / 2
select $"{o.Name} grade average: {averageGrade}";

// Join combines two collections together based on a condition


var inUseBooks = from o in students
join b in books on o.StudentID equals b.StudentID // Inner join
select new { o.Name, b.BookName }; // New collection using these types

// Display books that are checked out


foreach (var inUseBook in inUseBooks)
WriteLine($"{inUseBook.Name} checked out book: {inUseBook.BookName}");
// Output: Jonathan checked out book: C# Fundamentals
// Output: Jontahan checked out book: Microsoft Magazine
// Output: Maria checked out book: C# Fundamentals

// OrderBy sorts all items in a collection


IEnumerable<StudentInfo> students3 = from o in students
orderby o.Name // Ascending by default
select o;

// Groups bundle elements into groups based on the information specified


var bookGroups = from o in books
group o by o.BookName;

// Display information about the groups


foreach (var bookGroup in bookGroups)
{
WriteLine($"Group Key: {bookGroup.Key}");
foreach (var o in bookGroup)
WriteLine($"Book: {o.BookName} is being borrowed by studentID: {o.StudentID}");
WriteLine();
}
// Output: Group Key: C# Fundamentals
// Book: C# Fundamentals is being borrowed by studentID: 1
// Book: C# Fundamentals is being borrowed by studentID: 2
//
// Group Key: Microsoft Magazine
// Book: Microsoft Magazine is being borrowed by studentID: 1

ReadLine();
}
}
P a g e | 116

QUERY EXPRESSIONS: LINQ – METHOD CALL SYNTAX

Method call syntax provides the same results as the query syntax covered in the previous
section. All the clauses previously covered are also available through these simple method invocations
that use lambda expressions.

Example: Where clause

// Previous query syntax


IEnumerable<StudentInfo> students2 = from o in students
where o.Grade1 > 90
select o;

// Method call syntax


IEnumerable<StudentInfo> students3 = students.Where(o => o.Grade1 > 90);

Example: Where and select clause

// Previous query syntax


IEnumerable<string> students2 = from o in students
where o.Grade1 > 90
select o.Name;

// Method call syntax


IEnumerable<string> students3 = students.Where(o => o.Grade1 > 90).Select(o => o.Name);

Example: OrderBy and select clause

// Previous query syntax


IEnumerable<string> students2 = from o in students
orderby o.Name
select o.Name;

// Method call syntax


IEnumerable<string> students3 = students.OrderBy(o => o.Name).Select(o => o.Name);
P a g e | 117

DATABASE

Databases store a collection of information in an organized way that can easily be added,
deleted, and updated. In the following example, a local SQL database is created to demonstrate CRUD
(Create, Read, Update, Delete) of a database.

Walkthrough: Creating a database

1. Create a Console Application in Visual Studio: File -> New -> Project -> Visual C# -> Console App
(.NET Core). On the bottom of the New Project page change the Name to “StudentDB” and
change the Location to where you want to save the file.

2. Verify that Entity


Framework is
installed. Right click
on the project
“StudentDB” and
select “Manage NuGet
Packages”. Click the
“Browse” tab.
a. Browse for
“Microsoft.EntityFrameworkCore” and install if it is not installed.
b. Browse for “Microsoft.EntityFrameworkCore.Tools” and install if it is not installed.
c. Browse for “Microsoft.EntityFrameworkCore.SQLServer” and install if it is not installed.
P a g e | 118

3. Create a folder to store and setup the model.


a. Right click on the project “StudentDB” and select Add -> New Folder. Name it “People”.
b. Right click on the People folder and add a Class called Student.
4. Add the following code to the Student class to create the model.

class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Grade { get; set; }
}

5. Create an additional class in the People folder called “StudentDBContext”. This class will manage
the connection to the database.
6. The class StudentDBContext needs to inherit from the Entity Framework class DBContext.
a. Update the class to “class StudentDBContext : DbContext”.
b. To use DBContext, add “using Microsoft.EntityFrameworkCore;” to the top of the page.
7. To handle the information from the Student class model previously created, a DbSet is used.

8. The connection string is added to connect to the database. The class should now look like the
example below.

class StudentDBContext : DBContext


{
public DbSet<Student> Students { get; set; }

// Connect to database
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\MSSqLLocalDB;Database=StudentDatabase;Trus
ted_Connection=True;");
}
}
P a g e | 119

9. Use migration to create the database. The purpose of migration is to keep the database in sync
with the models.
a. Click on Tools -> Nuget Package Manager -> Package Manager Console.
b. In the Package Manager Console input “Add-Migration InitialMigration”. This scaffolds
the initial set of tables for the model. The database hasn’t been created yet, but this is
the schema it will use.
c. After pressing enter, notice that a new folder called “Migrations” was added to the
project. This folder contains the schema and other information the database will need.
d. In the Package Manager Console input “Update-Database”. The database isn’t created
yet; this will create the database.
10. Verify the database by using SQL Server Object Explorer. If it is not currently on the left side of
Visual Studio, then click on View -> SQL Server Object Explore. The database will be located at
SQL Server -> (localdb).. -> Databases -> StudentDatabase.

11. View the table created by expanding the StudentDatabase -> Tables and then right click on
dbo.Students -> View Data.
12. It is now possible to input data directly into the database table. Enter in a Name and Grade.
Make sure the Grade is a number. Notice a new row is created when data starts to be input and
multiple records can be entered. However, data is not usually input directly into the database.
13. Below is an example of adding items to a database by code. Adding this code snippet to the
Main method will add the two students every time the application is loaded.

using (var db = new StudentDBContext())


{
// Add the following students to Database
db.Students.AddRange(
new Student
{
Name = "Wyatt",
Grade = 95
},
new Student
{
Name = "Kristen",
Grade = 98
});

// Save the changes


db.SaveChanges();
}
P a g e | 120

In the example below, a “ForEach” loop is used to loop through an entire database table and
display the results.

Example: Display results

using (var db = new StudentDBContext())


{
foreach (var theStudent in db.Students)
WriteLine($"Name: {theStudent.Name} Grade: {theStudent.Grade}");
}

The example below will query the database table using the where keyword. When the “where”
keyword is used only results that match the search parameters will be returned.

Example: Where query and display results

using (var db = new StudentDBContext())


{
// Search for students named "Wyatt"
// To use the query Where below, use "Using System.Linq"
var studentInfo = db.Students.Where(x => x.Name == "Wyatt");

foreach (var theStudent in studentInfo)


WriteLine($"Name: {theStudent.Name} Grade: {theStudent.Grade}");
}

Using the contains keyword can provide flexibility to a search. For example, if a user searches
“Ces”, then the results will contain names that contain “Ces” such as “Cesar”.

Example: Contains

using (var db = new StudentDBContext())


{
var query = db.Students.Where(s => s.Name.Contains("Ces"));
}
P a g e | 121

Using the OrderBy keyword sorts the results numerically and alphabetically.

Example: OrderBy

using (var db = new StudentDBContext())


{
var query = db.Students.OrderBy(s => s.Name).ToList();
}

Other popular keywords are Average, Sum, Max, and Min. An example on how to get the Max
value is below.

Example: Max value

using (var db = new StudentDBContext())


{
var query = db.Students.Max(s => s.Age);
}

To remove items from a table, use RemoveRange or Remove. After removing the items,
SaveChanges must be called to update the database.

Example: Remove and save changes

using (var db = new StudentDBContext())


{
// Example 1: Remove students with RemoveRange and the Where query
db.Students.RemoveRange(db.Students.Where(x => x.Name == "Wyatt"));

// Example 2: Remove without needing Linq


foreach (var DeleteStudent in db.Students)
{
if (DeleteStudent.Name == "Matt")
db.Students.Remove(DeleteStudent);
}

// Save the changes


db.SaveChanges();
}
P a g e | 122

Use the select keyword to specify which columns are needed. This improves the speed of the
results returned.

Example: Select columns

using (var db = new StudentDBContext())


{
var query = db.Students
.Select(s => new { s.Name });
}

Example: Where and Select multiple columns

using (var db = new StudentDBContext())


{
var query = db.Students
.Where(s => s.Name == "Bill")
.Select(s => new { s.Name, s.Grade });
}

Using the join keyword combines information from two separate tables based on a common
attribute between the two. For example, table 1 contains a student with ID “5”, Name “Cesar”, and
Grade “98”. Table 2 contains StudentID “5” and age “25”. If ID matches StudentID, put the information
together (Name, Grade, and Age)

Example: Join multiple tables and display results

var query = (from a in db.Students // Database Table 1


join b in db.Students2 // Database Table 2
on a.ID equals b.StudentID // The two tables will need to have something in
common to compare; an ID is often used.
select new
{
a.Name,
a.Grade,
b.Age
});

foreach (var theStudent in query)


WriteLine($"Name: {theStudent.Name} Grade: {theStudent.Grade} Age: {theStudent.Age}"

You might also like