add converted md slides and images

- remove example lecture
main
borb 2 days ago
parent c5e91631d1
commit a796d64be7

@ -0,0 +1,165 @@
# Introduction to C# and .NET
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_0.png)
---
# Overview
Installing Visual Studio
A Brief History of .NET and C#
Creating Your First Application
Statements
Errors in Visual Studio 2022
Comments
# Installing Visual Studio
* Note: Visual Studio and Visual Studio Code are NOT the same thing
* Visual Studio is a full-blown IDE (integrated development environment)
* Visual Studio Code is more akin to text editors like Sublime Text, Atom etc.
* While both can be used in certain situations, the C# and ASP.NET portions of this training assume that you are using Visual Studio
* You can download the free version (Visual Studio Community) from [https://visualstudio.microsoft.com/vs/community/](https://visualstudio.microsoft.com/vs/community/)
* This downloads the setup executable for VS, which will be used to download all the modules needed (see the next slide)
# Installing Visual Studio (cont.)
* After launching the setup executable, you will be prompted to select the components to be installed along with VS. For our purposes you will need "ASP.NET and web development" portion, found in the "Workloads" tab
* Click "Install" found in the lower right corner to begin installing VS and the required components
* Note: The installation can be quite large (8 GB or more) depending on which components are already installed on your system, so we recommend using a personal hotspot if possible
* Multiple people downloading large amounts of data using the same public WIFI network will bog down the download speed for everyone
* After installing VS, you can skip the account creation portion
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_1.png)
# .NET
* .NET is Microsoft's software framework that turns your code (C#, F# or VB) into machine language
* Two types of .NET Frameworks:
* .NET Framework
* 2001
* Windows only
* Comes pre-installed with every Windows OS
* .NET Core
* 2016
* "Successor to .NET Framework"
* Open source! [https://github.com/dotnet/](https://github.com/dotnet/) _core_
* Cross-platform (Linux, Mac, Windows)
* We will be using .NET Core during this course as the old .NET Framework is pretty much legacy
* Base Class Library (BCL)
* A set of libraries that every .NET implementation uses
* The libraries consist of common activities, like classes and value types, that you will use to create your programs
* No need to reinvent the wheel with every new project
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
# C#
C# was developed for .NET Framework in 2000
Microsoft wanted a Windows exclusive competitor for Java
Easy to understand, general purpose, object oriented
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_2.png)
Source: [http://pypl.github.io/PYPL.html](http://pypl.github.io/PYPL.html)
# Creating a Console Application
Open Visual Studio 2022.
Select "Create a new project"
Type "console" to the search bar and select the following template:
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_3.png)
# Running a Console Application
To run your program, select "Debug" -> "Start Debugging" __or __ press F5 __or __ press the small play sign preceding your project name at the top middle
The template project should now run and print "Hello World!" to the console. Try changing the code so that it prints something else!
# C# Syntax - Statements
using System;
namespace MyAwesomeProgram
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Rows = statements
Curly brackets ' _{' _ and ' _}' _ mark the start and the end of different _bodies _ of statements
Semicolon at the end of some statements
When to use semicolon? Don't worry: Visual Studio will tell you
# C# Syntax - Errors in Visual Studio 2022
Why is this throwing an error?
Missing one closing curly bracket
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_4.png)
Hovering on the red underline will show a hint for the error:
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_5.png)
All errors can be displayed by pressing the red cross in the bottom:
![](imgs/1%20Introduction%20to%20C%23%20and%20NET_6.png)
# C# Syntax - Comments
There are two basic ways to comment in C#:
// This is a comment
/* This is a
multi
line
comment */
Any text inside a comment will not be executed
Use comments to explain your code or comment out actual code for testing and debugging
# Assignments
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/1.%20C%23%20Basics%20Assignments)

@ -0,0 +1,49 @@
# Introduction to Visual Studio
![](imgs/15%20Introduction%20to%20Visual%20Studio_0.png)
---
# Overview
* An IDE (Integrated development environment) by Microsoft for Windows
* Debug tools
* Used for C#, C++, etc
* Free Community edition
* Multiple versions released
* First version: 1997
* 2017, 2019, 2022…
# Windows
_Solution Explorer_ (CTRL+ALT+L) shows the files in the project
_Terminal _ (CTRL+Ö) for command line stuff, like using Git
# Moving windows around
![](imgs/15%20Introduction%20to%20Visual%20Studio_1.png)
* Drag and hold windows to move them around
* _Snap to layout_ window appears
* After moving a window to the right, you can pin it to see its title on the right
![](imgs/15%20Introduction%20to%20Visual%20Studio_2.png)
# Keyboard shortcuts
* CTRL+.
* If a type is missing, use this to add the needed using directive
* CTRL+R, then CTRL+R (seriously?)
* Rename variable
* Press Enter to confirm
* CTRL+C (without selecting), then CTRL+V
* Duplicate line
* ALT+Up, ALT+Down
* Move line up/down
# Gotchas
* Some actions are unavailable when your app is running
* Deleting files
* Adding new controllers

@ -0,0 +1,233 @@
# Static Members, Methods and Classes
![](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_0.png)
---
# Static Members
So far, we have used __non-static__ fields in our classes
This means, that each instance of the class holds its own version of the field, and changing the value of it only affects that instance:
class MyAwesomeClass
{
public int MyProperty { get; set; }
}
class Program
{
static void Main(string[] args)
{
MyAwesomeClass instance1 = new MyAwesomeClass();
MyAwesomeClass instance2 = new MyAwesomeClass();
instance1.MyProperty = 100;
instance2.MyProperty = 200; // instance1.MyProperty is still 100
}
}
# Static Members (continued)
Likewise, non-static class methods _have to _ be called through an instance:
class MyAwesomeClass
{
public void PrintText(string text) { Console.WriteLine(text); }
}
class Program
{
static void Main(string[] args)
{
MyAwesomeClass instance = new MyAwesomeClass();
instance.PrintText("Hello World"); // Outputs "Hello World"
MyAwesomeClass.PrintText("Hello World"); // Results in an error
}
}
![](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_1.png)
__Static fields are shared between all instances of a class__
Let's declare "MyProperty" property with the __static __ keyword. Now it can be referenced through the class type name, but not through the instance, as shown below:
class MyAwesomeClass
{
public static int MyProperty { get; set; } = 100;
}
class Program
{
static void Main(string[] args)
{
MyAwesomeClass instance = new MyAwesomeClass();
Console.WriteLine(MyAwesomeClass.MyProperty); // Outputs "100"
Console.WriteLine(instance.MyProperty); // Results in an error
}
}
![](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_2.png)
# Static Members - Example
In this example, a static field is used for keeping count on how many times the class has been instantiated:
class Person
{
public static int totalPersons = 0;
private string name;
public Person(string personName) // Person Constructor
{
name = personName;
++totalPersons;
}
public void PrintInfo()
{
Console.WriteLine("This person is called " + name + ".");
Console.WriteLine("There are " + totalPersons + " persons total.");
}
}
# Static Members - Example (continued)
Now let's instantiate a couple of persons and print their info:
class Program
{
static void Main(string[] args)
{
Person steve = new Person("Steve");
Person wendy = new Person("Wendy");
steve.PrintInfo();
wendy.PrintInfo();
}
}
![](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_3.png)
# Static Methods
Methods can also be static
What happens when you try to call a non-static method from a static method?
class Program
{
void PrintHelloName(string name)
{
Console.WriteLine("Hello, " + name);
}
static void Main(string[] args)
{
PrintHelloName(); // Will throw an error
}
}
![](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_4.png)
---
This is why until this point all example methods have been inside of the main function
# Static Classes
* Classes can also be made static
* Static classes cannot be instantiated
* All members of a static class also have to be static
* static class Styling
* {
* public static string fontFamily = "Verdana";
* public static float fontSize = 12.5f;
* }
* class Program
* {
* static void Main(string[] args)
* {
* Console.WriteLine
* ("Using font " + Styling.fontFamily + " " + Styling.fontSize + "px");
* // Outputs "Using font Verdana 12.5px"
* Styling = new Styling(); // Results in an error
* }
* }
# Exercise 1
Create a class Message which has two __static __ properties int TotalMessages and string LastMessage, and a __non-static __ property string MessageText.
Add a constructor which takes a string message as a parameter, increases TotalMessages by one and sets the value of LastMessage to message which is the parameter
Create a main loop which keeps asking the user for a new message. A new Message instance is then created with the user input message as an argument:
Message newMessage = new Message(message);
newMessage is then added to a list of messages, allMessages
Finally the static values Message.TotalMessages and Message.LastMessage are printed

@ -0,0 +1,289 @@
# Delegates and Events
![](imgs/11%20Delegates%20and%20Events_0.png)
---
# Overview
Delegates
Multicast Delegates
Anonymous Methods
Events
# Delegates
* __Delegates __ are reference type variables that hold a __reference to a method__ or multiple methods
* Class objects hold a reference to a class instance, delegate objects hold a reference to a method / methods
* Similar to function pointers in C and C++, or how any function in JavaScript works
* Allows for methods to be passed as variables, useful for creating, for example, events
# Creating a Delegate
Declare a delegate using the following syntax:
delegate \<return type> \<delegate name>(\<parameters>);
Example:
delegate void PrintDelegate(string output);
This creates a new delegate of type void, named PrintDelegate and one parameter of type string
The referenced method return and parameter types have to match the delegate!
# Referencing a Delegate
After creating the delegate, it can be instantiated and the method assigned to it with the method name:
delegate void PrintDelegate(string output);
static void Main(string[] args)
{
void PrintInLower(string text)
{
Console.WriteLine(text.ToLower());
}
PrintDelegate print = PrintInLower;
print("AaaBbbCcc"); // Outputs "aaabbbccc"
}
# Using Multicast Delegates
Delegates can be __composed of__ multiple methods using the "+" operator
Using the same PrintDelegate delegate as before, we could do this:
delegate void PrintDelegate(string output);
static void Main(string[] args)
{
void PrintInLower(string text)
{
Console.WriteLine(text.ToLower());
}
void PrintInUpper(string text)
{
Console.WriteLine(text.ToUpper());
}
PrintDelegate print = PrintInLower;
print += PrintInUpper;
print("AaaBbbCcc");
}
![](imgs/11%20Delegates%20and%20Events_1.png)
# Using Multicast Delegates (continued)
Methods can be removed from the delegate with the "-" operator:
delegate void PrintDelegate(string output);
static void Main(string[] args)
{
...
print -= PrintInLower;
print("AaaBbbCcc"); // Outputs "AAABBBCCC"
...
}
# Delegates - Example
Let's extend our previous example (without the "-=" part) by creating a new class called DelegateTest, and giving it a constructor that takes a PrintDelegate object as a parameter:
public class DelegateTest
{
public DelegateTest(PrintDelegate printDelegate)
{
printDelegate("This Method Was Called From Another Class!");
}
}
# Delegates - Example (continued)
Now we can create a new DelegateTest object and pass the delegate to the object constructor:
void PrintInLower(string text)
{
Console.WriteLine(text.ToLower());
}
void PrintInUpper(string text)
{
Console.WriteLine(text.ToUpper());
}
// Initialize new delegate which is composed of PrintInLower method
PrintDelegate print = PrintInLower;
// Add PrintInUpper method to the delegate
print += PrintInUpper;
// Send the delegate to the class constructor
DelegateTest delegateTest = new DelegateTest(print);
![](imgs/11%20Delegates%20and%20Events_2.png)
# Anonymous Methods
Delegates can be initialized anonymously (without a specified name)
Anonymous method in variable declaration:
delegate void PrintDelegate(string output);
bool printUpper = true;
PrintDelegate printCheckUpper =
delegate (string text)
{
if (printUpper)
Console.WriteLine(text.ToUpper());
else
Console.WriteLine(text);
};
printCheckUpper("I'm not angry!"); // Outputs I'M NOT ANGRY!
Notice that the actual method that prints the text is not declared anywhere
You can use an empty anonymous method to initialize a delegate which does nothing:
delegate void SomeDelegate();
class Program
{
static void Main(string[] args)
{
// Initialize an empty delegate, add method later...
SomeDelegate myDelegate = new SomeDelegate(delegate { });
}
}
# Events
* Consider the following Game class:
* class Game
* {
* Sound gameOverSound;
* Window gameOverScreen;
* // Some game logic here...
* // ...
* void OnGameOver()
* {
* gameOverSound.Play(); // This plays some sound
* gameOverScreen.Show(); // This shows some screen
* }
* }
* This raises a couple of problems:
* The Game class has to know about the Sound and Window classes
* Changes in either of the classes could break the code
* = Game is dependent of Sound and Window classes
---
Tight coupling
# Events (continued)
Events are signals that are raised by a __Publisher __ and received by a __Subscriber__
The publisher does not know or care what, if any, object receives the signal
Changes in the subscriber classes do not affect the publisher
# Events - Example
Events are created in two steps:
Declare a delegate
Declare a variable of the delegate with the event keyword
public delegate void GameOver();
class Game
{
public event GameOver GameOverEventHandler;
// Some game logic here...
// ...
}
# Exercise 1: A Rudimentary Event System
Create a console application for controlling a plant treatment system, that has three methods which print the following outputs:
| void ReleaseWater() | Releasing water... |
| :-: | :-: |
| void ReleaseFertilizer() | Releasing fertilizer... |
| void IncreaseTemperature() | Increasing temperature... |
Create a main loop where the user can switch each method on (= add to a delegate) by writing its name. All methods are off by default. (Hint: you can just use switch-case for defining which method should be added to the delegate)
If the user types run, all the methods that are on (= added to the delegate), will be executed.
![](imgs/11%20Delegates%20and%20Events_3.png)

@ -0,0 +1,295 @@
# Files and Streams
![](imgs/12%20Files%20and%20Streams_0.png)
---
# Overview
Files and Streams
Reading from a File
Writing to a File
JSON Serialization
JSON Deserialization
# Files and Streams
The .NET library contains classes for manipulating files and directories
The FileStream class contains methods for read and write operations for files
The goal is usually to turn the data in your code into an outside resource, such as a .txt file, and vice versa
Application Code
Stream writer / reader
String, int, ...
FileStream object
.txt, .csv, .png, ...
---
https://learn.microsoft.com/en-us/dotnet/api/system.io?view=net-7.0
# Using the File Class
To get started, add the following namespace to your project:
using System.IO;
System.IO provides basic directory and folder support, and allows reading and writing to files and data streams
Check if a file exists with the .Exists() method:
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
if (!File.Exists(path))
{
Console.WriteLine($"The file {path} does not exist.");
}
---
https://learn.microsoft.com/en-us/dotnet/api/system.io?view=net-7.0
# Reading from a File
Get the entire document as a string with File.ReadAllText
Get all lines of a document as a string array with File.ReadAllLines
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
if (!File.Exists(path))
{
Console.WriteLine($"The file {path} does not exist.");
}
else
{
var allLines = File.ReadAllLines(path);
foreach (string line in allLines)
Console.WriteLine(line);
}
# Writing to a File
Writing to a file is done with File.WriteAllText and File.WriteAllLines methods:
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
string[] lyrics = new string[]
{
"Hello",
"Is it me you're looking for",
"I can see it in your eyes",
"I can see it in your smile"
};
if (File.Exists(path))
{
File.Delete(path); // If file exists, deletes the old file
}
File.WriteAllLines(path, lyrics); // Creates a new file with lyrics
# Exercise 1: A Simple Parser
Create a console application which keeps asking the user for a string. Each string is added into a list of strings.
If the user returns an empty string, the program asks for a path to a .txt file.
If the file exists, its contents are replaced with each string written to a separate line. If not, a new file with the contents is created.
# JSON Serialization
* JSON (JavaScript Object Notation) is a way to represent code objects in text form, a "data-interchange format"
* Enables reading and writing series of objects into a text file
* Consists of two types of structures
* Objects, or unordered name-value pairs
* Ordered lists of values
* Language-independent, although the JSON notation resembles the C-family of languages (C#, Java, JavaScript etc.)
---
https://www.json.org/json-en.html
# JSON Serialization (continued)
* .NET projects do not directly support JSON serialization
* A __NuGet package__ for that exists, called __Newtonsoft.Json __
* Install the package from _Tools _ -> _NuGet Package Manager_ -> M _anage NuGet Packages for Solution…_
* Select _Browse_
* The _Newtonsoft.Json_ should be the topmost package. If not, search for it from the search bar
* Select the package, check the checkbox next to _Project _ and click _Install_
You can __serialize __ an object (e.g. a list) into a JSON string with the JsonConvert.SerializeObject() method:
class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
static void Main(string[] args)
{
List<Product> products = new List<Product>
{
new Product{Id=1, Name="Awesome Product"},
new Product{Id=2, Name="Terrible Product"}
};
string jsonString = JsonConvert.SerializeObject(products);
File.WriteAllText(@"C:\\Users\\OMISTAJA\\source\\repos\\Example\\Products.json", jsonString);
}
The contents of the output file Products.json are as follows:
![](imgs/12%20Files%20and%20Streams_1.png)
# JSON Deserialization
__Deserializing __ the contents of a JSON file into an object in your program can be done with the JsonConvert.DeserializeObject() method:
string json = File.ReadAllText(
@"C:\\Users\\Johannes\\source\\repos\\Luentoesimerkit\\Luentoesimerkit\\db.json");
List<Product> deserializedProducts = new List<Product>();
deserializedProducts = JsonConvert.DeserializeObject<List<Product>>(json);
foreach(Product product in deserializedProducts)
{
Console.WriteLine(product.Name);
}
# Exercise 2: Serializing Your Classes
Create a class Note with the properties int Id, DateTime TimeStamp and string Text.
Create a main loop that keeps asking the user for a new note.
After the user has entered each note, a new Note object is created with a running Id (1, 2, 3…), TimeStamp set to current time and Text is the inputted note. Each new note is added to a list of notes, allNotes.
Every time a new note is submitted, the allNotes list is serialized into a json file, "notes.json". Set the path to the current project path (you can get the path by right-clicking the project in solution explorer and selecting "Copy Full Path". Remember to change the file name!)
# FileStream
The files have to be opened before read/write and closed after
Behind the scenes, the ReadAll... and WriteAll… methods automatically do the opening and closing, as described in the Microsoft documentation:
![](imgs/12%20Files%20and%20Streams_2.png)
Writing to or reading only a part of the file requires opening and closing the file manually
This creates a __FileStream __ object that can be used for accessing parts of the file
# FileStream (continued)
When inserting string data into a file, it needs to be converted into bytes
string path = @"C:\\Users\\Public\\TestFolder\\TestWriteFile.txt";
int nOfLines = 4;
FileStream fs = null;
if (!File.Exists(path)) // If file does not exist
fs = File.Create(path); // create a new file and open it
else // If file exists
fs = File.OpenWrite(path); // open an existing file for writing
for (int i = 0; i < nOfLines; ++i)
{
string input = Console.ReadLine() + "\\n"; // Read user input, add newline
byte[] byteInput = new UTF8Encoding(true).GetBytes(input); // Get the string as a sequence of bytes
fs.Write(byteInput, 0, byteInput.Length); // Write the bytes at the end of the file
}
fs.Close(); // Close the file
# The Using Statement
From the Microsoft Documentation about the FileStream class:
![](imgs/12%20Files%20and%20Streams_3.png)
This means that wrapping the file handling in an __using __ block handles the opening and closing of the stream for you
The following reads the first 20 characters of a file and prints them to the console
string path = @"C:\\Users\\Public\\TestFolder\\TestFile.txt";
int nOfBytesToPrint = 20;
byte[] byteArray = new byte[nOfBytesToPrint];
if (!File.Exists(path))
Console.WriteLine($"The file {path} does not exist.");
else
using (FileStream fs = File.OpenRead(path))
{
fs.Read(byteArray, 0, nOfBytesToPrint);
};
// No need to close the file since it was handled inside of a using block
Console.WriteLine(Encoding.UTF8.GetString(byteArray, 0, byteArray.Length));

@ -0,0 +1,528 @@
# Generics, IEnumerable and LINQ
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_0.png)
---
# Generics
When using lists, you have to define the type of data that will be stored in the list, inside the angled brackets:
List<int> numberList = new List<int>(); // This list stores variables of type int
This means that list is a __generic__ class: it can contain data of any type
Classes, structs, interfaces and methods can also be generic
All the variables that are defined generic inside a generic container will be assigned a type only when the containing object/method is called
# Generics - Creating a Generic Class
class GenericClassExample<T>
{
public T value; // This value will be whatever type is specified at instantiation
public void PrintTypeAndValue()
{
Console.WriteLine
($"This class contains a variable of type {value.GetType()} and of value {value}");
}
}
class Program
{
static void Main(string[] args)
{
GenericClassExample<int> example = new GenericClassExample<int>();
example.value = 20;
example.PrintTypeAndValue();
}
}
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_1.png)
# Generics - Multiple Type Parameters
Generic classes can receive multiple types as parameters
class CustomContainer<T1, T2, T3>
{
public T1 First { get; set; }
public T2 Second { get; set; }
public T3 Third { get; set; }
}
class Program
{
static void Main(string[] args)
{
CustomContainer<int, string, DateTime> container
= new CustomContainer<int, string, DateTime>();
container.First = 10;
container.Second = "Testing.";
container.Third = DateTime.Now;
}
}
# Generics - Creating a Generic Method
void GenericMethodExample<T>(T value)
{
Console.WriteLine
($"This method was passed a variable of type {value.GetType()} and of value {value}.");
}
GenericMethodExample<string>("ABC");
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_2.png)
You could name the generic type as anything, e.g. \<GenericType>. It is named \<T> by convention.
# Exercise 1: Initializing a Populated List
Create a generic method GetPopulatedList\<T> which takes two parameters: T value and int length, and returns a new list of type T which is populated with the value variables and has a length of length.
Test your method out with a couple of different types and lengths:
List<string> list = GetPopulatedList<string>("Hello, there", 10);
foreach(string value in list)
{
Console.WriteLine(value);
}
# IEnumerable
Lists and arrays are both __collections __ that implement the __IEnumerable __ interface
All objects that implement the IEnumerable interface can be iterated with the foreach statement
IEnumerable<string> names = new string[] {"Harry", "Luke", "Harley"};
IEnumerable<string> days = new List<string> {"Sunday", "Monday", "Friday"};
foreach (string name in names)
Console.WriteLine(name);
foreach (string day in days)
Console.WriteLine(day);
# IEnumerable (continued)
The IEnumerable interface itself doesn't hold much functionality
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_3.png)
However, the LINQ library includes all the methods you would typically need to apply to IEnumerables, such as filtering
# LINQ
Some common query expressions occur repeatedly in code
E.g. trying to find an object with a certain id from an array:
IEnumerable<User> userArray = new User[2] // Initialize a new array of users
{
new User { Id = 0, Name = "Rene" } ,
new User { Id = 1, Name = "Ville" }
};
User FindObjectWithId(int id)
{
foreach (User user in userArray)
if (user.Id == id)
return user;
return null;
}
Console.WriteLine(FindObjectWithId(1).Name); // Outputs "Ville"
# LINQ (continued)
* Having to write your own method for each possible query operation (select, filter, sort…) would of course be nonsensical
* The List class includes some methods for manipulation, but...
* These only work on lists; not all IEnumerables (e.g. arrays) contain those methods
* Add to this all the different types of data (objects, SQL databases, XML, JSON…)
To introduce extensive query capabilities to all collection types, Language-Integrated Query (LINQ) was created
LINQ supports querying of objects and even XML and SQL data, directly in your code
Get started by adding the namespace to your project:
using System.Linq;
Here's the first example using LINQ:
IEnumerable<User> userArray = new User[2] // Initialize a new array of users
{
new User { Id = 0, Name = "Rene" } ,
new User { Id = 1, Name = "Ville"}
};
Console.WriteLine(userArray.First(user => user.Id == 1).Name); // Outputs "Ville"
The __First __ -method returns the first result that satisfies the expression in the parameters
The arrow syntax above is called a __lambda expression__
# Lambda Expressions
Lambda expressions are a quick way of writing one line methods
The "First" -method of LINQ takes a __delegate __ as a parameter
The following code would do exactly the same thing as the example in the previous slide:
// Parameter references an existing method
bool GetUserWithId(User user)
{
return user.Id == 1;
}
Console.WriteLine(userList.First(GetUserWithId).Name); // Outputs "Ville"
As would the following:
// The delegate is created inside the parameters as an anonymous method
Console.WriteLine(userList.First(delegate (User user)
{ return user.Id == 1; })); // Outputs "Ville"
# Lambda Expressions (continued)
Using LINQs "First" -query with...
...a method:
bool GetUserWithId(User user)
{
return user.Id == 1;
}
Console.WriteLine(
userList.First(
GetUserWithId).Name);
// Outputs "Ville"
...an anonymous method:
Console.WriteLine(userList.First(
delegate (User user)
{
return user.Id == 1;
}));
// Outputs "Ville"
...a lambda expression:
Console.WriteLine(userList.First(
user =>
user.Id == 1).Name);
// Outputs "Ville"
# Lambda Expressions - Example
Normal methods can also be declared using the arrow function
static void Main(string[] args)
{
// Method body assigned with lambda expression
string PrintCheckUpper(bool upper, string text) => upper ? text.ToUpper() : text;
PrintCheckUpper(true, "I'm not angry!"); // Outputs I'M NOT ANGRY!
}
# LINQ and Lambda Expressions
Going back to our LINQ example, it could be written without lambda expressions:
bool GetUserWithId(User user)
{
return user.Id == 1;
}
IEnumerable<User> userArray = new User[2] // Initialize a new array of users
{
new User { Id = 0, Name = "Rene" } ,
new User { Id = 1, Name = "Ville"}
};
Console.WriteLine(userArray.First(GetUserWithId).Name); // Outputs "Ville"
Here's the shorter version with lambda expression again:
Console.WriteLine(userArray.First(user => user.Id == 1).Name); // Outputs "Ville"
# LINQ Methods
LINQ contains methods for filtering, ordering, grouping, joining and selecting
Suppose we have a class Person that contains a property Country
The following performs filtering to persons object, returning only the persons whose country is of value "Finland":
List<Person> persons = new List<Person> {/* Insert data here */};
var queryResult = persons
.Where(person => person.Country == "Finland");
# LINQ Methods (continued)
| Method | Example | Description |
| :-: | :-: | :-: |
| Where | persons.Where(p => p.Country == "Finland") | Filters results based on an expression |
| OrderBy | persons.OrderBy(p => p.LastName) | Orders results based on one of its properties |
| Select | persons.Select(p => $"Dr. {p.LastName}") | Converts the enumerable into an another type based on an expression |
| Skip | persons.Skip(1) | Skips first N elements |
| Take | persons.Take(5) | Returns N elements |
| ToList | persons.ToList() | Converts IEnumerable to a list |
| ToArray | persons.ToArray() | Converts IEnumerable to an array |
---
Tässä on kaikki aritmeettiset operaattorit
| Method | Example | Description |
| :-: | :-: | :-: |
| Any | persons.Any(p => p.Country == "Finland") | Return true if at least one element satisfies a condition |
| All | persons.All(p => p.Age >= 18) | Return true if all elements satisfy a condition |
| FirstOrDefault | persons.FirstOrDefault(p => !p.Active) | Returns the first element that satisfies a condition, or null if not found |
| Count | persons.Count(p => p.FirstName == "Mauri") | Returns the count of elements that satisfy a condition, can be left blank to count all |
More LINQ methods can be found [here](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-7.0)
---
Tässä on kaikki aritmeettiset operaattorit
# LINQ - Example
Suppose we have a csv file authors.csv in our project directory
// using System.IO;
string path = @"C:\\some\\path\\authors.csv";
var authors = File.ReadAllLines(path)
.Skip(1) // Skip the first line which contains the column titles
.Select(line => // Using lambda expression, return the new Author objects
{
var columns = line.Split(',');
return new Author
{
Id = int.Parse(columns[0]),
Name = columns[1],
Description = columns[2]
};
})
.ToList(); // Turn the resulting IEnumerable into a list
authors is now an in-memory list containing all the authors from the original csv file. Note how methods can be chained!
# Query Syntax
An alternative way of using LINQ is with the __query syntax__
The following performs filtering to persons object:
var queryResult = from person in persons
where person.country == "Finland"
select person;
The __range variable __ person works like the range variable in a foreach loop in that it holds a copy of the current element in the persons variable
The where keyword specifies the condition for the filter
# LINQ Queries - Example
Suppose we have a class City that contains a property Description
The following would print the descriptions of all cities that have descriptions less than 100 characters long
IEnumerable Cities = new List<City> {/* Insert data here */};
var filteredResult = from city in Cities
where city.Description.Length < 100
select city;
foreach (City result in filteredResult)
Console.WriteLine(result.Description);
# Extension Methods vs Query Syntax
* In the previous examples, we used the query syntax of LINQ
* Both the methods and queries do pretty much the same thing
* It is up to you which syntax you want to use
* The method syntax works like any normal C# methods
* The query syntax might be more approachable to those who are familiar with SQL
var methodResult = persons
.Where(person => person.Country == "Finland");
var queryResult = from person in persons
where person.Country == "Finland"
select person;
All queries listed here: [https://www.tutorialsteacher.com/linq/linq-standard-query-operators](https://www.tutorialsteacher.com/linq/linq-standard-query-operators)
# ToArray() and ToList() Methods
Notice that the LINQ queries return an IEnumerable
If you need to use arrays or lists, you need to call the ToArray() or ToList() methods:
string[] strings = new string[] { "Timo", "Pekka", "Taina", "Kalle" };
string[] queryResult = strings
.Where(s => s.StartsWith('T'));
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_4.png)
string[] strings = new string[] { "Timo", "Pekka", "Taina", "Kalle" };
string[] queryResult = strings
.Where(s => s.StartsWith('T'))
.ToArray(); // This works
# Exercise 2: Filtering Names
Download this file of names and add it to your project folder: [https://raw.githubusercontent.com/dominictarr/random-name/master/names.txt](https://raw.githubusercontent.com/dominictarr/random-name/master/names.txt)
Read all the contents into a string array with File.ReadAllLines()
Create a main loop where the user is asked for a string. Print the total number of names which contain that string.
If there are less than 10 resulting names, print the names as well
# Exercise 3: Queries on Object Lists
Expand on the exercise 2.
Create a new class User with two properties, int Id and string Name
If the number of filtered names is less than 10, create a list of Users with those names and a running Id
Sort the list of users by the length of the Name property
Print the names and id:s of the users in the sorted list
# Going Further: Extension Methods
Recap: IEnumerable itself only contains one method
How does the LINQ library suddenly add all these methods to our Enumerables?
This is possible with extension methods:
[https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)

@ -0,0 +1,318 @@
# Exceptions,
Threads and Tasks
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_0.png)
---
# Exceptions
* Exceptions are problems that occur during the lifetime of the program
* Typical exceptions are IndexOutOfRangeException and NullReferenceException
* IndexOutOfRangeException occurs when trying to access an element of an object using an index greater than the number of elements in that object
* NullReferenceException occurs when trying to reference a variable that has not been assigned a value
# Exceptions (continued)
* There should be some kind of system to check for these problems so that even if they do occur, the application does not crash
* For example, if a user tries to read from a file that does not exist, the user should be given an informative error message instead of closing the application
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_1.png)
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_2.png)
# try - catch
Wrap the code that could result in an exception in a __try __ block
Wrap the code that should execute if an exception occurs in a __catch __ block
string path = @"C:\\Users\\Public\\TestFolder\\WriteText.txt";
try
{
string text = System.IO.File.ReadAllText(path);
}
catch(DirectoryNotFoundException e)
{
Console.WriteLine($"The path {path} does not exist.");
}
# throw
__throw __ - keyword results in the exception that is caught in the catch block
This can be used if you want to execute some code before stopping the execution of the program
string path = @"C:\\Users\\Public\\TestFolder\\WriteText.txt";
try
{
string text = System.IO.File.ReadAllText(path);
}
catch (IOException e)
{
Console.WriteLine("An exception occurred.");
Console.WriteLine("Logging exception information...");
Console.WriteLine($"Exception: {e.Message}");
throw;
}
# finally
__finally __ block executes after try-catch regardless of whether an exception occurred or not
This is useful for closing unmanaged objects like database connections and file streams
try
{
// Open a database connection or file stream
}
catch (SystemException e)
{
// Do this if connection / stream fails
}
finally
{
// Release the unmanaged resources from memory
}
# Exercise 1: Debugging Exceptions
Create a savings calculator which asks the user for a target amount of money the user is aiming for (in integers), and the users monthly salary. For parsing, use the int.Parse() method instead of int.TryParse().
The program then calculates the number of months it will take the user to reach the goal.
After displaying the result, the user is then asked for a path to a _folder _ where the result is then saved as _months\_until\_target.txt._
Try your program with different user inputs. Try to intentionally break your program and find as many exceptions as you can.
Handle the exceptions with exception handling, and inform the user of each exception with an appropriate message.
# Threads
* You might have time consuming functionality in your program, like
* heavy algorithms and mathematical calculations, or
* reading a large amount of data from a file
* You could also have some continuous stream of data being read, like
* serial signal
* In case of time consuming methods, it might be a bad idea to wait for the execution to finish before continuing the main program
* This would show up to the user as the program being stuck
* At the very least, there could be some progress bar to indicate that the program hasn't crashed
* In the case of continuous execution, there needs to be some way to read the stream and execute the main program at the same time
# Threads (continued)
.NET supports __multithreading __ and classes to add new threads are included in the base class library
using System.Threading;
Separate tasks can be executed simultaneously on separate __threads__
Separate threads run on different cores in the processor
All threads have access to the resources allocated to your program
Initialize a ThreadStart object with the method to be threaded as the argument:
public static void PrintInteger()
...
ThreadStart printIntegerStart = new ThreadStart(PrintInteger);
Initialize a Thread object with the ThreadStart object set as the argument, and start the new thread with Thread.Start() method:
Thread printIntegerThread = new Thread(printIntegerStart);
printIntegerThread.Start();
# Threads - Example
class Program
{
public static void PrintInteger()
{
Console.WriteLine("Thread started.");
int val = 0;
while (true)
{
Thread.Sleep(100);
Console.WriteLine("Current value: " + val);
++val;
}
}
static void Main(string[] args)
{
ThreadStart printIntegerStart = new ThreadStart(PrintInteger);
Console.WriteLine("Starting thread...");
Thread printIntegerThread = new Thread(printIntegerStart);
printIntegerThread.Start();
Console.WriteLine("Main thread continuing.");
}
}
The PrintInteger method prints a value, waits for 0.1sec, increases the value, prints it again and so on
The method keeps executing indefinitely, but the main thread continues execution as well
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_3.png)
# Threads (continued)
You can create as many threads as you like:
ThreadStart printIntegerStart = new ThreadStart(PrintInteger);
Console.WriteLine("Starting thread...");
Thread printIntegerThread = new Thread(printIntegerStart);
printIntegerThread.Start();
Thread printIntegerThread2 = new Thread(printIntegerStart);
printIntegerThread2.Start();
Thread printIntegerThread3 = new Thread(printIntegerStart);
printIntegerThread3.Start();
# Exercise 2: Threaded Loading
Create a method public static void LoadData() which simulates loading resources by printing progress from 0% to 100%. Increase the progress in a loop with 1% increments. Use the Thread.Sleep() method to wait 10 ms between each increment.
Create a main loop where each time the user presses enter, the LoadData() method is executed on a separate thread.
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_4.png)
---
Näytä ekstrana, miten tämä tehdään käyttäen luokan metodia eri luokan arvoilla
# Tasks
* In some cases you want to continue working on some tasks while others are queued to be executed
* For example, after sending a server request, you might want to begin some tasks immediately and others only after a response has been received
* Following [this great analogy](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/) from Microsoft docs, a cook doesn't have to wait for the eggs to be ready to begin brewing coffee or cooking bacon; instead, the cook would begin all tasks simultaneously
* Threading won't help here; even if there was one cook (thread) for each task, they would all have to wait for the oven to heat up. One cook can just well do all the tasks (cooking) alone.
# Tasks - Continued
To create an asynchronous method, assign it with the async keyword. It is good practice to end the method name with Async
The method should return a value of the type that is specified in the angled brackets (if your task doesn't return a value, leave the brackets out)
Inside the method, call an asynchronous method with the await keyword:
static async Task<int> MyMethodAsync()
{
byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/");
return content.Length;
}
This method can now be called asynchronously:
Task<int> myMethodResult = MyMethodAsync();
# Tasks - Example
![](imgs/14%20Exceptions%2C%20Threads%20and%20Tasks_5.png)
class Program
{
static async Task<string> GetResultAsync()
{
int waitTime = 5000;
await Task.Delay(waitTime); // Replace this with your time consuming async functionality
return new string($"The task took {waitTime / 1000} seconds to finish.");
}
static void Main(string[] args)
{
Console.WriteLine("Starting operation...");
Task<string> resultTask = GetResultAsync();
Console.WriteLine("Operation has been started.");
Console.WriteLine("In the meantime, tell me something nice: ");
string somethingNice = Console.ReadLine();
resultTask.Wait(); // Wait for the task to complete
Console.WriteLine(resultTask.Result);
Console.ReadKey();
}
}
# Exercise 3: Asynchronous Loading
Re-create the exercise 2, but instead of using separate threads for "loading the data", use an asynchronous method LoadDataAsync()

@ -0,0 +1,133 @@
# Design Patterns in C#
![](imgs/15%20Design%20Patterns%20in%20C%23_0.png)
---
# Overview
The Singleton Pattern
Dependency Injection
# The Singleton Pattern
* In some cases, it would make no sense to create an instance of a class every time it's members need to be accessed
* For example, a shared resource manager that is being called from multiple classes
* While a static class could be used for this, there are some problems:
* As stated in the previous slide, static classes can only have static members
* Static classes cannot be instantiated, so a reference to them cannot be passed around as a parameter
* Static classes cannot inherit from other classes or implement interfaces
* [And many more... ](https://www.c-sharpcorner.com/UploadFile/akkiraju/singleton-vs-static-classes/)
# The Singleton Pattern (continued)
* The __singleton __ class is a class that benefits from all the perks of a non-static class (non-static members, inheritance, referencing…), but only one (or zero) instances of it ever exists during the lifetime of your application
* For example, reading from / writing to a file that should be accessible to multiple clients, should be made into a singleton
* Instead of every client directly accessing the same file (and possibly causing massive performance issues), the singleton is instantiated once and a reference to it is provided to clients
* The singleton could take care of queueing the read/write requests and be the only entity accessing the actual file
A singleton implementation could look something like this:
class Singleton
{
private static Singleton instance = null;
private Singleton() { }
public void MySingletonFunction()
{
Console.WriteLine
("This function is accessible from everywhere!");
}
public static Singleton Instance
{
get
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
class Program
{
static void Main(string[] args)
{
Singleton.Instance.MySingletonFunction();
// Outputs "This function is accessible from everywhere!"
}
}
The exact implementation of the singleton is out of the scope of this course, but it is important to understand that it exists and what its purpose is
Multitude of examples for different use cases are available and can be found by googling
# Dependency Injection
* Traditionally, when new objects of classes are instantiated, the consuming class handles the creation of the objects
* A lot of classes change their functionality throughout the development of any project
* This means that also _every single_ consuming class has to change
* This is called __"tight coupling"__
* What if, instead of directly creating the objects, they were provided by some interface that takes care of the creation?
* This way, even if the base class changes, the consuming classes won't care because they only know about the provider
* This provider is called __Container, __ and the functionality being injected is called __Service__
* In ASP.NET, this container system is built in
---
Show an example
Dependency injection in ASP.NET:
public class HomeController : Controller
{
private readonly IUserRepository \_userRepository;
public HomeController(IUserRepository userRepository)
{
\_userRepository = userRepository;
}
// User repository including all users is now accessible in HomeController
}
# Design Patterns
If the concepts of a singleton and dependency injection flew over your head, don't worry about it
The important thing is to know they exist so that when they come up again in ASP.NET, you have already familiarized yourself with the terms and understanding the logic behind ASP.NET becomes less overwhelming
There are many more design patterns, see the material [here](https://www.c-sharpcorner.com/UploadFile/bd5be5/design-patterns-in-net/)
![](imgs/15%20Design%20Patterns%20in%20C%23_1.png)

@ -0,0 +1,324 @@
# Variables & Types
![](imgs/2%20Variables%20and%20Types_0.png)
---
# Overview
Variables
Data Types
Arithmetic Operators
Increment & Decrement
Assignment Operators
Strings
Character Constants
String Interpolation
# Variables
* Variable can be thought of as a name for a certain point in computer's memory.
* Using this name we can access the value on the computer's memory
* We can read the value
* We can manipulate the value
* On more practical terms: We can assign values to named variables.
# C# Syntax - Declaring Variables
Every variable declaration in C# requires the type and the name of the variable, for example:
int x;
You can assign a value for declared variables:
x = 25;
Variable declaration with value can be executed with one line:
int x = 25;
using System;
namespace MyAwesomeProgram
{
class Program
{
static void Main(string[] args)
{
int a = 25;
int b = 10;
Console.WriteLine(a - b);
}
}
}
Everything within a console application executes inside the Main body
This program prints the value "15" to the console
# Why we use variables?
Variables are key ingredients in programming.
We don't need to know the exact values when we write the code but the values can be given later while the program is executed
As an example we can take an input from a user and store it to a variable and use that value somewhere later in our program
# What is a data type?
* Data type tells to a computer what type of data is stored in a variable.
* Data types are commonly divided into two categories:
* Primitive data types
* Reference data types
* Here we go through the primitive data types
* We dig deeper on the differences of these data types later in the Classes and Objects -section
# Primitive Data Types in C#
| __Type__ | __Represents__ | __Range__ | __Default Value__ |
| :-: | :-: | :-: | :-: |
| __bool__ | __Boolean value__ | __True or False__ | __False__ |
| __byte__ | __8-bit unsigned integer__ | __0 to 255__ | __0__ |
| __char__ | __16-bit Unicode character__ | __U +0000 to U +ffff__ | __\\0'__ |
| __decimal__ | __128-bit precise decimal values with 28-29 significant digits__ | __(-7.9 x 1028 to 7.9 x 1028) / 100 to 28__ | __0.0M__ |
| __double__ | __64-bit double-precision floating point type__ | __(+/-)5.0 x 10-324 to (+/-)1.7 x 10308__ | __0.0D__ |
| __float__ | __32-bit single-precision floating point type__ | __-3.4 x 1038 to + 3.4 x 1038__ | __0.0F__ |
| __int__ | __32-bit signed integer type__ | __-2,147,483,648 to 2,147,483,647__ | __0__ |
More types listed here:
[https://www.w3schools.com/cs/cs\_data\_types.asp](https://www.w3schools.com/cs/cs_data_types.asp)
# Data Types in C# - Example
double airPressure = 1.2; // Use generally for everything
decimal accountBalance = 1.2m; // Use for accuracy (e.g. financial applications)
float bulletSpeed = 1.2f; // Use only when you know the precision will be enough (in other words, don't use)
bool loggedIn = false;
char previousInput = 'b';
# Assignments (variables)
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/2.1.%20Variables%20&%20Types)
# Assignments (data types)
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/2.2.%20Data%20Types)
# What are arithmetic operations?
The arithmetic operations are common mathematical operations:
addition
subtraction
multiplication
division
modulus (remainder, in Finnish jakojäännös)
exponentiation
Earlier we used an _arithmetic operator _ to subtract b from a:
Console.WriteLine(a - b);
# Arithmetic Operators
| Operator | Name | Example | Description |
| :-: | :-: | :-: | :-: |
| + | Addition | a + b | Adds together two values |
| - | Subtraction | a - b | Subtracts one value from another |
| * | Multiplication | a * b | Multiplies two values |
| / | Division | a / b | Divides one value by another |
| % | Modulus | a % b | Returns the division remainder |
| ++ | Increment | a++ | Increases the value of a variable by 1 |
| -- | Decrement | a- | Decreases the value of a variable by 1 |
---
Tässä on kaikki aritmeettiset operaattorit
# Exercise 1: Trying Out Variables
Create a new console application as we did in the last exercise and declare two variables of type __double__ _._
Assign different values for those variables.
Print the __sum__ , __difference__ , __fraction __ and __product __ of those values to the console.
# Increment & Decrement
Increment and decrement operations are operations that can be used to increment or decrement a variable value by 1.
Most programming languages implement these operations
Addition example: int a = 3; a = a + 1; _// a is now 4_ Can be written with increment: int a = 3; a++; _// a is now 4_
Decrement is like increment but with just subtraction
Substraction example: int a = 3; a = a - 1; _// a is now 2_ Can be written with decrement: int a = 3; a--; _// a is now 2_
Increment and decrement operators can be written in two ways. So sometimes you may also see this: int a = 3; --a; _// a is now 2_ _ _ ++a; _// a is now 3_
This will do the same thing as a++ and a--. There is a small difference between these syntaxes though.
int a = 3;const _ _ b = _ _ a++; _// b will be 3_ Console.WriteLine(a); _// this will print out 4_ Here the assignment to b happens before incrementing a, thus b will be assigned value 3.
int a = 3;const _ _ b = _ _ ++a; _// b will be 4_ Console.WriteLine(a); _// this will print out 4_ Here the assignment to b happens after incrementing a, thus b will be assigned value 4.
---
Täällä voi helposti demota: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Increment
# Assignment Operators
We have used the assignment operator ' __='__ for assigning values for variables:
int x;
x = 25;
__Notice __ the difference between '=' and the conditional '=='!
'=' is used for assigning values for variables, '== is used for comparing values
| Operator | Example | Same As |
| :-: | :-: | :-: |
| = | x = 5 | x = 5 |
| += | x += 5 | x = x + 5 |
| -= | x -= 5 | x = x - 5 |
| *= | x *= 5 | x = x * 5 |
| /= | x /= 5 | x = x / 5 |
| %= | x %= 5 | x = x % 5 |
---
Tässä on joitakin asetusoperaattoreita, lisäksi loogiset (ei käydä tässä)
# Operators - Example
int uppercaseLetters = 2;
uppercaseLetters += 4; // is now 6
int specialCharacters = 2;
specialCharacters *= 2; // is now 4
Console.WriteLine(uppercaseLetters);
Console.WriteLine(specialCharacters);
This outputs 6 and 4
# Strings
String is a special type, which contains an array of characters. You can declare and assign strings like any other type of variables:
string name = "Johannes Kantola";
You can concatenate multiple strings with the '+' operator:
string firstName = "Johannes";
string lastName = "Kantola";
string fullName = firstName + " " + lastName;
Console.WriteLine(fullName); // Outputs "Johannes Kantola"
# Character Constants
Character constants are preceded by a backslash '\\' and can be used for formatting strings
'\\n' represents a newline in the following example:
string firstName = "Johannes";
string lastName = "Kantola";
string fullName = firstName + "\\n" + lastName;
Console.WriteLine(fullName);
/* This outputs
Johannes
Kantola
*/
All character constants: [https://www.tutorialspoint.com/csharp/csharp\_constants.htm](https://www.tutorialspoint.com/csharp/csharp_constants.htm)
# String Interpolation
Concatenating multiple variables into one string with the '+' operator quickly becomes tedious
It's much easier to use __string interpolation __ by prefixing your target string with '$' and inserting the variables inside curly brackets '{ }':
string animal = "Dog";
string sound = "Woof";
Console.WriteLine($"{animal} says {sound}!");
// Outputs "Dog says Woof!"
# String Formatting
You can add __format strings__ to change the way variables are interpolated into a string
Add the format string after your variable, separated by a colon (:)
You can find an overview of format strings and a handy list of both standard and custom strings [here](https://learn.microsoft.com/en-us/dotnet/standard/base-types/formatting-types)
double pi = 3.141592653;
Console.WriteLine($"Pi to three digits: {pi:G3}");
// Outputs "Pi to three digits: 3.14"
# Console.ReadLine()
For the next exercise, you'll need the Console.ReadLine() method. The method pauses the program, waits for an input stream from the console that pops up, and returns the value of the input:
string userInput = Console.ReadLine();Console.WriteLine(userInput);
![](imgs/2%20Variables%20and%20Types_1.png)
# Exercise 2: weekday survey
Create a console application which asks the user which weekday it is and assigns the answer to a string variable.
Print "Have a nice weekday!" to the console where weekday is replaced with the string the user wrote.
# Assignments (arithmetic operations)
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/2.3.%20Arithmetic%20Operations)

@ -0,0 +1,263 @@
# Conditionals
![](imgs/3%20Conditionals_0.png)
---
# Overview
Conditionals
if and else
Logical Operators
# Conditionals
Less than: a < b
Less than or equal to: a <= b
Greater than: a > b
Greater than or equal to: a >= b
Equal to a == b
Not Equal to: a != b
Conditionals return true or false, meaning the result can even be allocated into a variable if needed
bool areEqual = (a == b);
# if , else and else if statements
double temperatureInOulu = 2.3;
double temperatureInIvalo = -10.9;
if (temperatureInOulu > temperatureInIvalo)
{
Console.WriteLine("Oulu is warmer than Ivalo");
}
else if (temperatureInOulu < temperatureInIvalo)
{
Console.WriteLine("Ivalo is warmer than Oulu");
}
else
{
Console.WriteLine
("Oulu and Ivalo have the same temperature");
}
__if __ statements are executed in order
The first statement with a __true __ condition is executed
If no statement holds a true value, __else __ is executed
This outputs "Oulu is warmer than Ivalo"
# ! -Operator
Console.WriteLine(!true); // Outputs false
bool itsColdOutside = true;
if(!itsColdOutside)
{
Console.WriteLine("It's warm outside.");
}
The ! -operator flips the boolean value __ __
# The switch statement
The __switch __ statement compares the parameter value (here: the __path __ variable) with the value of each __case__
Only the matching code is executed
If no match is found, the default code block is executed
This outputs "Here's the catalogue!"
break ends the case and exits the switch: the code will not compile if omitted
string path = "/browse";
switch (path)
{
case "/browse":
Console.WriteLine("Here's the catalogue!");
break;
case "/contact":
Console.WriteLine("Here's our contact info.");
break;
default:
Console.WriteLine("No such path!");
break;
}
# Scope of Variables
Variables declared inside of blocks are called __local variables__ ; they are only accessible inside of that block.
int a = 0;
if(a < 10)
{
// Variable 'b' is only accessible inside of this if block
int b = 1;
b = 2; // This works
}
b = 3; // This throws an error
# Assignment Operators
We have used the assignment operator ' __='__ for assigning values for variables:
int x;
x = 25;
__Notice __ the difference between '=' and the conditional '=='!
'=' is used for assigning values for variables, '== is used for comparing values
# Logical Operators
'&&', '||' and '!' mean the logical AND, OR and NOT operators
For example,
int a = 1;
int b = 3;
int c = 5;
Console.WriteLine(a < b && a < c);
outputs "True"
| Operator | Name | Example | Description |
| :-: | :-: | :-: | :-: |
| && | AND | a && b | Returns true if __both__ variables are true.b is not evaluated if a == false. |
| || | OR | a || b | Returns true if __one or both__ variables are true. b is not evaluated if a == true. |
| ! | NOT | !a | __Negates__ boolean value (true becomes false and vice versa) |
| ^ | XOR | a ^ b | Exclusive OR: returns true if __only __ a == true __OR only__ b == true. |
| & | Logical AND | a & b | Returns true if __both__ variables are true. Both variables are always evaluated. |
| | | Logical OR | a | b | Returns true if __one or both__ variables are true.Both variables are always evaluated. |
---
Tässä on kaikki aritmeettiset operaattorit
# Operators - Example
This outputs "Strong password!"
int uppercaseLetters = 2;
uppercaseLetters += 4; // is now 6
int specialCharacters = 2;
specialCharacters *= 2; // is now 4
if (uppercaseLetters >= 6 && specialCharacters >= 2)
{
Console.WriteLine("Strong password!");
}
else
{
Console.WriteLine("Weak-ass password...");
}
# Exercise 1:
Create a console application which asks the user which weekday it is and assigns the answer to a string variable.
Using a switch-case, calculate the days remaining until next Monday.
If the result is more than 3, print "Have a nice week!". Otherwise, print "Have a nice weekend!".
# Exercise 2:
Create a console application which lets the user input a note.
If the length of the note is less than 30, the program prints the current time and the note, separated with a tab. Otherwise, the date and the note are printed to a separate line.
Tip: Use DateTime.Now.ToString() for current time. Use .Length after your message variable to get the length of the message.
# One More Thing...
If a code block following a statement only has one line of code, you can write the code without using curly brackets:
int baa = 49;
if (baa > 20)
Console.WriteLine("Baa");
else
Console.WriteLine("Not baa!");
if (baa > 20) Console.WriteLine("Baa");
else Console.WriteLine("Not baa!");
You may see code where this is done. However, we highly recommend you not to use this syntax as it is highly prone to [errors](https://www.leadingagile.com/2018/01/the-goto-fail-bug-as-a-coaching-tool/) .
# Get Help
All the basics covering the syntax in C# are covered here:
[https://www.tutorialspoint.com/csharp/index.](https://www.tutorialspoint.com/csharp/index.htm) [htm](https://www.tutorialspoint.com/csharp/index.htm) [l](https://www.tutorialspoint.com/csharp/index.htm)
[https://www.w3schools.com/cs/default.asp](https://www.w3schools.com/cs/default.asp)
# Assignments
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/3.%20Conditionals)

@ -0,0 +1,246 @@
# Loops
![](imgs/4%20Loops_0.png)
---
# Overview
While Loop
For Loop
Nested Loops
Breaking Out of Loops
# Loops
Loops are useful when you need to repeat a block of code multiple times and to avoid code like this:
Console.WriteLine(count);
++count;
Console.WriteLine(count);
++count;
Console.WriteLine(count);
// Yuck! Nobody wants to see this.
Loops can also be used for iterating through arrays and lists (more on those later)
# while Loop
_while_ loop keeps executing its code block as long as the condition in its statement is true:
int count = 0;
while(count < 4)
{
Console.WriteLine(count);
++count;
}
// Outputs '0', '1', '2' and '3'
# do..while Loop
_do..while_ works the same way as while, but it executes the code at least once and checks the condition at the end:
int count = 0;
do
{
Console.WriteLine(count);
++count;
} while (count < 4);
// Outputs '0', '1', '2' and '3'
# for Loop
_for _ loops are used when the number of iterations are predefined
for loop executes in three inherent steps:
for (/*initial value*/;/*condition*/;/*increment*/)
{
/* Code to be executed */
}
The initial value is set before the first iteration. The condition is checked before each iteration, and the increment is executed after each iteration.
# for Loop (continued)
Try to understand the following two examples:
for (int i = 0; i < 4; ++i)
{
Console.WriteLine
("Current: " + i);
}
/* Outputs
Current: 0
Current: 1
Current: 2
Current: 3
*/
for (int i = 8; i > 0; i -= 2)
{
Console.WriteLine
("Current: " + i);
}
/* Outputs
Current: 8
Current: 6
Current: 4
Current: 2
*/
We start from zero, print the current value and add one until the value is no longer under four.
We start from eight, print the current value and remove two until the value is no longer larger than zero.
for (int i = 8; i > 0; i -= 2)
{
Console.WriteLine
("Current: " + i);
}
for (int i = 0; i < 4; ++i)
{
Console.WriteLine
("Current: " + i);
}
# Nested Loops
Nothing prevents you from using a loop inside another loop:
int columns = 3;
int rows = 4;
for (int i = 0; i < columns; ++i)
{
for (int j = 0; j < rows; ++j)
{
// Console.Write doesn't add a line break after printout
Console.Write("(" + j.ToString() + "," + i.ToString() + ")");
}
Console.WriteLine("");
}
![](imgs/4%20Loops_1.png)
# Breaking Out of Loops
To stop the execution of a loop completely, use the _break _ -keyword:
int i = 0;
while(true)
{
++i;
if(i > 3)
break;
}
// i is now 4
To skip the current iteration, use the _continue _ -keyword
int i = 0;
while(i < 10)
{
++i;
if (i % 2 == 0)
continue;
Console.WriteLine(i);
}
// Prints every odd number from 1 to 10
# Exercise 1: The Main Loop
At the heart of every dynamic program, there is something called the _event loop _ a.k.a the _main loop. _ Create a console application which keeps asking the user for an input, until the user inputs "quit".
Expand the program so that if the user inputs "help", a dialog shows up which shows the command and explanation for the command for both quit and help commands.
![](imgs/4%20Loops_2.png)
# Exercise 2: Prime Numbers
Prime number is a number greater than 1 that is not a product of two small numbers, i.e. cannot be divided into a whole number. (Wikipedia: [https://en.wikipedia.org/wiki/Prime\_number](https://en.wikipedia.org/wiki/Prime_number) )
Create a console application which prints all the prime numbers between 0 .. 40
![](imgs/4%20Loops_3.png)
# Assignments
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/4.%20Loops)

@ -0,0 +1,204 @@
# Arrays and Lists
![](imgs/5%20Arrays%20and%20Lists_0.png)
---
# Overview
Arrays
Multidimensional Arrays
Lists
Iterating a List
Foreach
# Arrays
Arrays are a collection of variables of the same type, which allocate neighboring memory locations
A single value in this collection is called an __element__
Arrays can be __declared __ with square brackets following the type of the elements:
int[] userIds;
Declaring an array does not yet allocate space from memory
# Arrays (continued)
__Initialize __ an array with a length of 3 using the following syntax:
int[] userIds = new int[3];
__Assign a value__ to an element in an array by specifying the index in square brackets:
userIds[0] = 104;
Indexing starts from 0, so the above line assigns a value of 104 to the first element of the array
You can also create an array containing values with one statement:
string[] names = new string[3] { "Johannes", "Rene", "Ville" };
The same works without specifying the length in the brackets:
double[] balances = new double[] { 1.3, 200.3, 9332.14 };
# Multidimensional Arrays
C# supports multidimensional arrays:
char[,] letters = new char[3, 4]
{
{'a', 'b', 'c', 'd'},
{'e', 'f', 'g', 'h'},
{'i', 'j', 'k', 'l'}
};
Console.WriteLine(letters[1, 3]); // Outputs "h"
# Lists
The .NET Framework Class Library offers another way to hold multiple variables: the _List _ object
Declaration and initialization:
List<int> userIds = new List<int>();
Value assignment:
userIds[0] = 22;
# Lists (continued)
The key benefit of using Lists lies in its built-in functionalities
![](imgs/5%20Arrays%20and%20Lists_1.png)
You can see a list of available methods in VSC2019 by following a variable with a dot
# Arrays vs Lists
The memory allocation of an array is static/fixed, but list memory is dynamic
This allows the flexible mutation of lists, meaning you can always add or remove and hence change change the length of the list without issues
![](imgs/5%20Arrays%20and%20Lists_2.png)
# Arrays vs Lists (continued)
When to use arrays and when lists?
Use __arrays __ if you need __high performance__
Use __lists __ if you need support for __list operations__
# Iterating an Array With for Loop - Example
string[] names = new string[]
{
"Harry Potter",
"Luke Skywalker",
"Harley Quinn"
};
for(int i = 0; i < names.Length; ++i)
{
Console.WriteLine(names[i]);
}
![](imgs/5%20Arrays%20and%20Lists_3.png)
# Iterating a List
You can iterate the elements of a list with a for loop the same way as an array
Just use List.Count instead of Array.Length
List<int> numbers = new List<int>() { 1, 5, 3 };
int sum = 0;
for (int i = 0; i < numbers.Count; ++i)
{
sum += numbers[i];
}
// sum is now 9
# foreach Statement
There is one more statement to use to iterate arrays and lists: the foreach statement
foreach is useful when you have to execute code for each element of an array or a list:
string[] names = new string[]
{
"Harry Potter",
"Luke Skywalker",
"Harley Quinn"
};
foreach (string name in names)
{
Console.WriteLine(name);
}
![](imgs/5%20Arrays%20and%20Lists_4.png)
# foreach Statement (continued)
However, foreach creates a copy of each element in the object so the element cannot be mutated directly:
![](imgs/5%20Arrays%20and%20Lists_5.png)
Performance-wise, using foreach is also more costly because it uses more memory space
---
Instead, create a new list
# Exercise 1: Expanding the Console Application
Continue working on the command line application you created in "The Main Loop" exercise. Add a new command "add" which prompts the user to write a note.
After the user has inputted the note, it is saved to a list, and the program returns back to listening to commands.
Add another command "list" which prints all the saved notes.
Add one more command "remove" which prints all the saved notes with the index of the note, and then prompts the user for a number. After entering the number the corresponding note is deleted from the list.
( __Note__ : you can use int.Parse() -method to parse the user input string to an integer)
# Assignments
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/5.%20Arrays%20&%20Lists)

@ -0,0 +1,270 @@
# Methods
![](imgs/6%20Methods_0.png)
---
# Overview
Functions
Methods
Parameters
Return Values
Scope of Methods
# What is a function?
* Functions are self contained modules of code that accomplish a specific task.
* Function is basically a block of code that can be executed over and over again in the program
* Instead of writing the same code over and over again to the program, it can be written only once as a function
* Functions can get data, _parameters_ , from the _caller_
* Functions can return data, _return value_ , to the caller
* Defining parameters and return values are optional, not all functions have both and some have neither!
# Function execution
* When a function is called the program leaves the current section of the code and begins to execute the first line of code inside the function.
* The program execution comes to the line of code where the function call is
* The program enters the function
* Instructions inside the function are executed from top to bottom
* Remember scopes: The variables defined inside the function are not visible outside the function!
* The program leaves the function and returns to the point where the function call was and continues the execution
* If function returned any data, it can be used where the function was called
# Methods
In C#, __methods __ are functions which are inside of a class
Since the main function is inside of a class, all functions in C# are actually just called methods
* A methods are executed only when it is __called__
* For example, Console.WriteLine() is a method which contains more complex code to print stuff on to the console
* Instead of writing all that complex stuff at every printout, you can just use the short method call Console.WriteLine()
* The use of methods reduces repetitive code, adds modularity and makes designing your programs easier
# Methods - Example
![](imgs/6%20Methods_1.png)
class Program
{
static void Main(string[] args)
{
void PrintBlock()
{
Console.WriteLine("---------------------");
Console.WriteLine("| This is cool but |");
Console.WriteLine("| you wouldn't want |");
Console.WriteLine("| to write this |");
Console.WriteLine("| block of code |");
Console.WriteLine("| every time! |");
Console.WriteLine("---------------------");
}
PrintBlock();
PrintBlock();
PrintBlock();
}
}
* In this example, we declared a new method called PrintBlock
* Finally the method was called three times
* Each time the entire code inside the method was executed
* The void statement means that the method does not return anything
* More on that later
# Parameters
Sometimes you want to pass data into the method when calling it
This is done by adding __parameters __ to the method declaration, inside the brackets:
void PrintSum(int val1, int val2)
{
int sum = val1 + val2;
Console.WriteLine("Sum of " + val1 + " and " + val2 + " is " + sum);
}
The values to be passed are set as __arguments __ in the method call, inside the brackets:
PrintSum(2, 5); // Outputs "Sum of 2 and 5 is 7
PrintSum(5, 5); // Outputs "Sum of 5 and 5 is 10
# Parameters - Example
![](imgs/6%20Methods_2.png)
static void Main(string[] args)
{
int centuriesPrinted = 0;
void PrintCentury(int century)
{
centuriesPrinted++;
Console.WriteLine("Current century: " + century);
Console.WriteLine("Total centuries printed: " + centuriesPrinted);
}
for (int i = 0; i < 500; i += 100)
{
PrintCentury(i);
}
}
# Optional Parameters
You can give a parameter a default value by assigning it in the method declaration
This makes the parameter optional
double CircleArea(double radius = 0)
{
double area = Math.PI * radius * radius;
return area;
}
Console.WriteLine(CircleArea()); // This outputs 0
Console.WriteLine(CircleArea(2)); // This outputs 12,56637...
# Exercise 1
Write two methods Sum and Difference, which both have two parameters of type int, named value1 and value2. Sum should print "The sum of __*value1*__ and __*value2*__ is __*sum*__ ", and Difference should print "The difference of __*value1*__ and __*value2*__ is __*difference*__ .
Call the methods from the main method multiple times with different values.
# Return Values
The return value of a method is __returned __ with the return keyword:
double radius = 2;
Console.WriteLine(CircleArea(radius)); // Outputs 12,56637...
double CircleArea(double radius)
{
double area = Math.PI * radius * radius;
return area;
}
In the first examples, the method declarations started with the void expression, which means that the method doesn't return anything
Here the method was declared as type double, which means that the method has to return a variable of type double
# Multiple Return Values
It is possible to return multiple values in the form of a __tuple__ :
(string, string) FirstAndLastName(string fullname)
{
string[] names = fullname.Split(' ');
return (names[0], names[names.Length - 1]);
}
(string first, string last) = FirstAndLastName("Hans \\"Dolph\\" Lundgren");
Console.WriteLine($"First name: {first}, last name: {last}");
// Outputs "First name: Hans, last name: Lundgren"
If only one value from a tuple is needed, you can use a __discard __ (\_)
// Only last name is allocated to a variable
(\_, string lastName) = FirstAndLastName("Arnold Alois Schwarzenegger");
# Scope of Methods
The variables declared inside of a method are __local variables__ and only accessible inside of that method
void ScopeExample()
{
// Variable 'a' is only accessible inside of this method
int a = 10;
a = 20; // This works
}
a = 30; // This throws an error
# Exercise 2
Write a method that takes a string as a parameter and prints the total number of spaces in that string.
Without using the string.Trim() method, modify the method so that it removes the spaces in a string and returns the new string.
(Hint: You can iterate a string just like arrays and lists.)
![](imgs/6%20Methods_3.png)
# Exercise 3
Write a method that takes a string as a parameter and prints each unique letter in that string.
Write a new method that takes a string as a parameter and prints the number of each unique letter in the string.
![](imgs/6%20Methods_4.png)
# Exercise 4
Write a method that takes a 10 digit number as a parameter and divides individual digits into even and odd arrays. Method should return both arrays.
Remember to check that method accepts only numbers.
# Assignments
[Assignments about this topic can be found here](https://gitea.buutti.com/education/academy-assignments/src/branch/master/C%23%20Basics/6.%20Methods)

@ -0,0 +1,558 @@
# Classes and Objects
![](imgs/7%20Classes%20and%20Objects_0.png)
---
# Overview
Namespaces
Classes
Object Variables
Access Specifiers
Class Members
Constructors
Value & Reference Types
Enum
# Namespaces
Using namespaces helps you to organize the scope of globally available data in your project, meaning that related objects in a well-named namespace makes it easy to import what you need
By default, when creating a new project and adding classes in Visual Studio, everything is contained within a namespace named after your project name
If you need a class or an enum to be accessible from anywhere, create it within that namespace and set it as public
// Note that namespaces can have
// subdirectories, as Models here
namespace MyAwesomeApp.Models
{
public class Student
{
}
}
// This is how you would use the
// Student class in other code
using MyAwesomeApp.Models
# Classes
__Classes __ in C# are blueprints for a __type __ of __object__
We have already used a class named _Program _ when creating a new console application:
![](imgs/7%20Classes%20and%20Objects_1.png)
---
You could even create new instances of Program
* If we wanted, we could just write the entire program with thousands of lines of code on one page inside the main function
* This kind of program would of course be impossible to work with within a group or organization:
* No one should have to scroll through tens of thousands of lines of code to find that one line that causes problems…
* At least make them browse through hundreds of classes instead :)
* Classes provide __encapsulation __ which result in __shorter files__ , __less repetitive code__ and overall __better readability__
# Creating a Class
You can create a new class by writing
class Student
{
}
Create variables inside a class just like before inside the Program class:
class Student
{
int id;
string name;
}
Variables declared directly inside classes are called __fields.__
# Referencing a Class
New instances of a class can be created with the __new __ keyword
All instances of a class have exactly the same fields and methods, but they can have different values
In the following example a few __objects __ of __type __ Student are created
However, these objects have no functionality yet
namespace MyAwesomeApp
{
class Student
{
}
class Program
{
static void Main(string[] args)
{
Student student1 = new Student();
Student student2 = new Student();
Student student3 = new Student();
}
}
}
# Object Variables
The variables inside of an object can be accessed with the '.' operator
However, the following syntax results in an error:
| Student class: | Program class: |
| :-: | :-: |
| class Student{ int id;} | class Program{static void Main(string[] args){ Student student = new Student(); student.id = 12345678;}} |
![](imgs/7%20Classes%20and%20Objects_2.png)
Let's fix the previous example by changing the _ _ __access specifier__ of the 'id' variable to __public__ :
| Student class: | Program class: |
|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------:|
| class Student{ public int id;} | class Program{static void Main(string[] args){ Student student = new Student(); student.id = 12345678;}} |
| | |
The value of the variable 'id' of the object 'student' is now 12345678
# Access Specifiers
__Access specifiers__ can be used to get additional level of protection inside classes
Variables specified with __private __ are accessible only inside the containing class
Variables specified with __public __ are accessible outside of the class
The __default __ access for any variable is private!
class Student
{
int id; // Accessible only inside the class
private string name; // Accessible only inside the class
public string address; // Accessible everywhere within the namespace
}
Continuing on the class in the previous slide, if we follow the 'student' variable with a dot, VS intellisense will only suggest the 'address' variable, because it was the only public variable of the 'Student' class
![](imgs/7%20Classes%20and%20Objects_3.png)
# Classes - Example
class Student
{
public int id;
public string name;
}
class Program
{
static void Main(string[] args)
{
Student student1 = new Student();
Student student2 = new Student();
student1.id = 22225555;
student1.name = "Johannes Kantola";
student2.id = 44441111;
student2.name = "Rene Orosz";
Console.WriteLine(student1.name); // Outputs Johannes Kantola
}
}
# Exercise 1
Create a console application that has a class User which contains two fields: string userName and string password
Create a main loop where the user is asked repeatedly for a new username and password. The values are stored to a new User instance and that instance is saved to a list of users
Print all stored usernames every time a new user is created
# Class Methods
As mentioned in the previous lecture, we can create methods inside of our classes:
class Person
{
public string firstName;
public string lastName;
public string FullName()
{
return firstName + " " + lastName;
}
}
class Program
{
static void Main(string[] args)
{
Person someDude = new Person();
someDude.firstName = "Johannes";
someDude.lastName = "Kantola";
Console.WriteLine(someDude.FullName());
// Outputs Johannes Kantola
}
}
If the method is public, it can be called from outside of the class
# Constructors
Constructors are class methods which are called once the object is initialized
Constructors are created by creating a class method with the same name as the class:
class User
{
public User()
{
Console.WriteLine
("New user created!");
}
}
| | |
| :-: | :-: |
class Program
{
static void Main(string[] args)
{
User user = new User();
// Outputs "New user created!"
}
}
In Visual Studio, just write "ctor" and press tab twice to quickly create a constructor
# Constructors with Parameters
You can pass in parameters to the constructor at initialization:
class Car
{
private string model;
private int year;
private int doors;
public Car(string modelName, int modelYear)
{
model = modelName;
year = modelYear;
doors = 5;
}
}
class Program
{
static void Main(string[] args)
{
Car lada = new Car("Niva", 1984);
Car ford = new Car("Focus", 2010);
// Both cars have 5 doors by default
}
}
# Exercise 2
Create a console application with a class Animal, that contains
two strings: name and sound, and
a method Greet() that prints " __*name*__ says __*sound*__ !"
Create a few animals with different names and sounds
Call their greet methods from the main program
# Properties
When working with C#, you will eventually see __properties __ being used at some point
Properties allow the manipulation of private fields from outside of the class:
class User
{
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
}
class Program
{
static void Main(string[] args)
{
User admin = new User();
admin.Id = 12345678;
Console.WriteLine(admin.Id);
// This outputs 12345678
}
}
# Auto Properties
Auto properties are a shorthand version of the same:
class User
{
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
User admin = new User();
admin.Id = 12345678;
Console.WriteLine(admin.Id);
// This outputs 12345678
}
}
In Visual Studio, just write "prop" and press tab twice to quickly create an auto property
# Properties
* __Why use properties if we could just use public fields?__
* We don't always want to expose the exact same variable that is used inside of the class, to outside
* Properties allow class fields to be __read-only__ or __write-only__ :
* public int Id { get; } // This field is read-onlypublic int Password { private get; set; } // This field is write-only
* Properties are supported in __interfaces__ , while fields are not
* We will cover interfaces later
* There are a bunch of other reasons, but they are outside the scope of this course
---
Lets say we have a variable in our class which is queued for calculating something important
Now some other class changes that variable -> Problem
# Value and Reference Types
* If this program is executed, what will be the output?
* int, double, char and other primitive data types are of __value type__
* The variable stores the __actual data__ in memory
* Every copy of the variable will be stored in a separate location
* class Program{ static void Main(string[] args) { int user = 1; int otherUser = user; user = 2; Console.WriteLine( "Value of otherUser: " + otherUser); }}
![](imgs/7%20Classes%20and%20Objects_4.png)
* When this program is executed, what will be the output?
* Strings, Arrays and Classes are of __reference type __
* The variable stores the address of the data being stored in memory
* Every copy of the variable points to the same address
class Program
{
static void Main(string[] args)
{
User user = new User();
user.id = 1;
User otherUser = user;
user.id = 2;
Console.WriteLine(
"Value of otherUser.id: " + otherUser.id);
}
}
class User
{
public int id;
}
![](imgs/7%20Classes%20and%20Objects_5.png)
Location in memory
int userId = 42;
int otherUserId = userId;
| 42 |
| :-: |
| 42 |
Changing the value in the object will affect all variables referencing it!
| points to |
| :-: |
| points to |
User user = new User(42);
User otherUser = user;
| user { id = 42 } |
| :-: |
# Exercise 3
Classes and enums can be created to a separate file. To quickly create a new class, right mouse click you project (not solution) name in solution explorer -> Add -> Class… Name your class "TestClass"
Back in your main method, create an instance of TestClass. The compiler should not give any errors.
Now rename the namespace that your TestClass is in, to "TestNamespace". Go back to your main method. The TestClass instantiation should not work anymore. Try to fix that without going back to TestClass.
# Exercise 4
Modify previous solution by using methods and class.

@ -0,0 +1,302 @@
# Inheritance & Abstract Classes
![](imgs/8%20Inheritance%20%26%20Abstract%20Classes_0.png)
---
# Overview
Inheritance
Abstract Classes
Enums
# Inheritance
Classes can be made to inherit functionality of some other class
If class B inherits class A, all of the (public) functionality in class A is also available in class B
A is called the __base class__ (or parent class) and B is called the __derived class __ (or child class)
Use the " __:"__ symbol to make a class inherit from another
Try to understand the following example:
| class Animal |
| :-: |
| -Eat()-Sleep() |
| class Dog : Animal |
| :-: |
| -Bark() |
| class Cat : Animal |
| :-: |
| -Meow() |
Animal can eat
Animal can sleep
Dog can eat
Dog can sleep
Dog can bark
Cat can eat
Cat can sleep
Cat can meow
# Inheritance - Example
class Animal
{
public void Eat() { Console.WriteLine("Eating..."); }
public void Sleep() { Console.WriteLine("Sleeping..."); }
}
class Cat : Animal
{
public void Meow() { Console.WriteLine("Meow!"); }
}
class Dog : Animal
{
public void Bark() { Console.WriteLine("Bark!"); }
}
class Program
{
static void Main(string[] args)
{
Dog pluto = new Dog();
pluto.Eat(); // Outputs "Eating..."
pluto.Bark(); // Outputs "Bark!"
}
}
# Inheritance
All the objects deriving from the same base class can be referenced with the base class name:
Animal whiskersAnimal = new Cat();
Animal plutoAnimal = new Dog();
However, only the methods of the base class are available for objects of the base class type:
plutoAnimal.Eat(); // Outputs "Eating..."
plutoAnimal.Bark(); // Error
An object of base class type can be __casted __ into the child class type:
Dog pluto = (Dog)plutoAnimal;
pluto.Bark(); // Outputs "Bark!"
# Abstract Classes
* In some cases you want the base class to be made __abstract__
* Objects of an abstract class cannot be instantiated
* For example, where would you need a generic Animal by itself?
* Make a class abstract with the abstract keyword:
* abstract class Animal
* {
* public void Eat() { Console.WriteLine("Eating..."); }
* public void Sleep() { Console.WriteLine("Sleeping..."); }
* }
* class Program
* {
* static void Main(string[] args)
* {
* Animal animal = new Animal(); // This will throw an error
* }
* }
Instead, the methods are accessible through a derived class:
abstract class Animal
{
public void Eat() { Console.WriteLine("Eating..."); }
public void Sleep() { Console.WriteLine("Sleeping..."); }
}
class Pig : Animal
{
public void Squeal() { Console.WriteLine("Squeee!"); }
}
class Program
{
static void Main(string[] args)
{
Pig pig = new Pig();
pig.Sleep(); // Outputs "Sleeping..."
pig.Squeal(); // Outputs "Squeee!"
}
}
If you know you only need the functionality of the abstract class, instantiate the new class as a type of abstract class:
abstract class Animal{ public void Eat() { Console.WriteLine("Eating..."); } public void Sleep() { Console.WriteLine("Sleeping..."); }}class Pig : Animal{ public void Squeal() { Console.WriteLine("Squeee!"); }}class Program{ static void Main(string[] args) { Animal pig = new Pig(); pig.Sleep(); // Outputs "Sleeping..." pig.Squeal(); // This will throw an error }}
---
This is called abstraction, which is one of the key concepts of OOP
# Exercise 1
Create the classes Animal, Dog, Cat and Pig. Animal is the same as before (strings name and sound and the Greet() method). Dog, Cat and Pig inherit Animal
Give Dog, Cat and Pig some fields and/or methods specific to that animal
Create a few instances of Dog, Cat and Pig classes, and add them to a new list of Animals, named "allAnimals"
Loop through allAnimals with the foreach statement, and call the Greet() method of each animal
# Enum
__Enum __ (short for enumeration) is a data type for holding a set of constant (immutable) names
Enums can be useful when you have a number of items or states that are predefined, for example, weekdays
Create the enum type with the enum keyword:
enum Weekday{ Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}
New instances of the enum can only be assigned one of the values within:
Weekday currentDay = Weekday.Monday;
# Enum - Example
In this example, enum is used to keep track of the state of the program:
enum ProgramState
{
Login,
Menu,
Exit
}
static void Main(string[] args)
{
ProgramState currentState = ProgramState.Login;
while (true)
{
switch (currentState)
{
case ProgramState.Login:
// Switch current state to Menu after logging in
break;
case ProgramState.Menu:
// Switch current state to Exit if user exits
break;
case ProgramState.Exit:
// Exit the program with an exit message
break;
}
}
}
# Going Further: Object Oriented Programming
* The instances that are created with the new -keyword are objects. This is literally what Object Orientation refers to: packing functionality into these reusable variables that are holding some data and can be passed around
* The key concepts of OOP are
* Encapsulation
* Inheritance
* Abstraction, and
* Polymorphism
# OOP: Encapsulation
Earlier we created classes which hold properties and methods, which are only accessible elsewhere _after _ instantiating an object of the class
All the functionality is encapsulated inside of the class instead of lying around in the codebase
All the functionality made available _only when it is needed _ by instantiating an object of the class
# OOP: Inheritance
As shown in the lecture slides, inheritance allows you to write some functionality once, and then create separate classes which all share that same functionality
This removes the need to write the same code inside every class
# OOP: Abstraction
When your class contains a lot of complicated functionality, it doesn't always make sense to reveal everything when the class is used
Instead, reveal only the parts that the user (you, a workmate, etc) actually need, with abstraction
Parable: The user of a microwave doesn't have to know about the complicated circuitry inside of the microwave. Only the buttons are revealed
# OOP: Polymorphism
This concept becomes more clear after we have covered interfaces
Polymorphism refers to multiple classes having the same method but with different functionality
This reduces the need for massive if-else and switch..case statements

@ -0,0 +1,270 @@
# Interfaces
![](imgs/9%20Interfaces_0.png)
---
# Overview
Interfaces
Interfaces or Inheritance?
# Interfaces
* In addition to abstract classes, __interfaces __ are a way to achieve abstraction to your program
* Interfaces are classes that have __no internal functionality__
* Interfaces describe the methods and properties that a class has to have when implementing the interface
* Think of it as a _contract_ : by __implementing __ an interface, the class _has to_ _use _ all the methods and properties that are defined in the interface
* As with abstract classes, interfaces cannot be instantiated directly
* It wouldn't make any sense as interfaces have no implementation
* Interfaces are way more commonly used than abstract classes
# Creating an Interface
* Define an interface using the interface keyword instead of class:
* interface IUser
* {
* int Id { get; set; }
* string Name { get; set; }
* void GetUserStatistics();
* }
* Interface names should begin with the capital I letter to more easily identify them as interfaces and not classes
* Notice that interfaces can contain both properties and methods but not fields
* Methods are declared without the method body (no implementation)
* The methods are implemented on the classes that uses the interface
# Implementing an Interface
Implement an interface just like you would inherit a class:
class User : IUser
{
}
The compiler will now throw a bunch of errors saying that the User class does not implement the properties and methods defined in the interface
Let's fix that by defining those now
# Implementing an Interface (continued)
class User : IUser
{
public int Id { get; set; }
public string Name { get; set; }
public void GetUserStatistics()
{
// Some code here
}
}
The interface is now fully implemented and the compiler is happy
The interface do not dictate _how_ the methods are implemented, those just need to be implemented.
To quickly implement the interface, click the IUser interface name and click the light bulb -> implement interface.
# Implementing Multiple Interfaces
* Unlike with inheritance, classes can implement multiple interfaces
* In contrast, classes can only inherit from one base class
* This is done by separating the interfaces with a comma:
* class Rock : IPickable, IThrowable, ICrushable
* {
* // Code that implements IPickable, IThrowable and ICrushable
* }
# Why Use Interfaces?
Interfaces allow common functionality among classes that are otherwise unrelated to each other
In those cases, inheriting from some shared base class wouldn't make sense
Consider the following example:
public void DeleteData(IDeletable data)
{
data.Delete();
}
The above method accepts _any _ type of object that implements IDeletable, regardless of other functionality
# Interface or Inheritance?
| class Dog |
| :-: |
| -Eat()-Sleep()-WagTail() |
| class Human |
| :-: |
| -Eat()-Sleep()-Contemplate() |
| class Bear |
| :-: |
| -Eat()-Sleep()-Hibernate() |
All classes could inherit from a base class Animal, which has methods Eat() and Sleep()
Should the base class be abstract? Depends on your program: do you ever need an object that can only Eat() and Sleep()?
| class Tree |
| :-: |
| -Grow()-Photosynthesize() |
| class Human |
| :-: |
| -Grow()-Move() |
| class Car |
| :-: |
| -Move()-Explode() |
It wouldn't make sense to use inheritance here, since there is no functionality that is shared between all classes
Instead you could make two interfaces: IGrowable and IMovable
# Interfaces - Example
Let's make a program that has two lists: one for all objects that can move (IMovable) and one for all objects that can be carried (ICarryable)
Finally every movable object is moved and carryable object is carried
interface IMovable
{
void Move();
}
interface ICarryable
{
void Carry();
}
class Elephant : IMovable
{
public void Move()
{
Console.WriteLine("The elephant is moving'");
}
}
class Cat : IMovable, ICarryable
{
public void Move()
{
Console.WriteLine("The cat is moving'");
}
public void Carry()
{
Console.WriteLine("You are carrying the cat");
}
}
class Rock : ICarryable
{
public void Carry()
{
Console.WriteLine("You are carrying the rock");
}
}
class Program
{
static void Main(string[] args)
{
Elephant elephant = new Elephant();
Cat cat = new Cat();
Rock rock = new Rock();
List<IMovable> movables = new List<IMovable>{ elephant, cat };
List<ICarryable> carryables = new List<ICarryable>{ cat, rock };
foreach (IMovable movable in movables)
movable.Move();
foreach (ICarryable carryable in carryables)
carryable.Carry();
}
}
![](imgs/9%20Interfaces_1.png)
# Exercise 1: A Web of Relations
Create a console application that has an interface IInfo, and two classes Product and Category, which both implement IInfo.
Inside IInfo, declare a property InfoText and a method PrintInfo
Implement the property and method in Product and Category
Initialize a couple of products and categories, with info texts of your choice
Create a list of type IInfo, and add the products and categories to it
Create a main loop, where each time the user presses enter, all the info texts inside the list are printed
# Exercise 2: The IComparable Interface
Create a program that sorts a list of shapes by area, using the [IComparable](https://docs.microsoft.com/en-us/dotnet/api/system.collections.icomparer?view=netcore-3.1) interface, which is used by the List.Sort() method to know whether the elements should come before or after each other in the list.
Start by creating 4 classes: __Shape__ , __Square__ , __Triangle__ and __Circle__ . Square, Triangle and Circle inherit from Shape. Shape implements the __IComparable\<Shape>__ __ __ interface.
Shape has a public property double Area. Square, Triangle and Circle have to have constructors to calculate the area: Square and Triangle with length and height, and Circle with radius.
The CompareTo(Shape? other) method should return 1 if the area is greater than what is being compared with (Shape other), 0 if the areas are equal, and -1 if the area is smaller.
Try out your solution by creating a couple of squares, triangles and circles in a list of shapes, and sorting the list with the .Sort() method. Print the areas in the sorted array with a foreach loop. They should be printed in an increasing order.

File diff suppressed because one or more lines are too long

@ -1,64 +0,0 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: N. Example Lecture
---
# Example Lecture
<!-- headingDivider: 5 -->
<!-- class: invert -->
## Section
- This line appears instantly
* This line appears by pressing spacebar
* This line has an inline code `variable`
```js
console.log("Here's a coloured JavaScript code block");
console.log("Remember indentation so it's revealed after the bullet point.");
```
* This line has an inline LaTeX maths equation $c = \frac{a^2}{\sqrt{b}}$
* Here's a maths block:
$$
F(x) = \int_a^b f(x) dx
$$
<!-- _footer: Footers are exclusive to presentation; they are not shown in the webpage markdown document -->
## Columns
<div class='columns' markdown='1'>
<div markdown='1'>
![](imgs/buuttilogo.png)
* Basic image example
</div>
<div markdown='1'>
![width:800px](imgs/buuttilogo.png)
* Wider image
</div>
</div>
* This line is outside the columns and goes from left all the way to the right
## Setup
* In VS Code, install the extensions
* [Marp for VS code](https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode)
* So you can see the slideshow preview when editing.
* [Markdown all in one](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one)
* [Markdown table formatter](https://marketplace.visualstudio.com/items?itemName=fcrespo82.markdown-table-formatter)
* *Right click > Format document* makes tables pretty
* [Save and run](https://marketplace.visualstudio.com/items?itemName=wk-j.save-and-run)
* An HTML version of the lecture is created on save
* See [settings.json](./.vscode/settings.json)
* Add filenames to `notMatch` if a HTML on save is not needed

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Loading…
Cancel
Save