Merge branch 'main' of gitea.buutti.com:education/csharp-basics

main
borb 2 weeks ago
commit 7aad3cf2d7

@ -1,3 +1,4 @@
wsl bash renamePptx.sh
call convertPptxToMd.bat
REN img imgs

@ -0,0 +1,3 @@
for f in *.pptx; do
mv -- "$f" "$(echo "$f" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
done

@ -68,10 +68,10 @@
},
"exercise slide" : {
"scope": "markdown",
"prefix": "\"exercise invert\"",
"prefix": "exercise",
"body": [
"## Exercise $0.",
"<!--_class: exercise -->",
"<!--_class: \"exercise invert\" -->",
],
"description": "Exercise slide colors"
},

@ -5,7 +5,7 @@
{
"match": "\\.md$",
"notMatch": "README\\.md$",
"cmd": "marp \"${fileDirname}\\${fileBasename}\" -o \"${fileDirname}\\${fileBasenameNoExt}-slides.html\" --html true",
"cmd": "marp \"${fileDirname}\\${fileBasename}\" -o \"${fileDirname}\\${fileBasenameNoExt}-slides.html\" --html true --theme \"${fileDirname}\\.themes\\buutti.css\"",
"useShortcut": false,
"silent": false
},

File diff suppressed because one or more lines are too long

@ -0,0 +1,198 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: 10. Static Members, Methods and Classes
---
# Static Members, Methods and Classes
<!-- headingDivider: 5 -->
<!-- class: invert -->
## Static Members
### Non-static members
* So far, we have used *__non-static__* fields in our classes
* Meaning that each instance of the class holds its own version of the field, and changing the value of it only affects that instance:
```csharp
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
}
}
```
---
* Likewise, non-static class methods **_have to_** be called through an instance:
```csharp
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
}
}
```
<div class='centered'>
![w:500px](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_1.png)
</div>
### Static members
* Let's declare a property `MyProperty` with the `static` keyword
* It can be referenced *through the class*, but ***not*** through the instance:
```csharp
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
}
}
```
<div class='centered'>
![w:600px](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_2.png)
</div>
### Static members: An example
* In this example, a static field is used for keeping count on how many times the class has been instantiated:
```csharp
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.");
}
}
```
---
* Now let's instantiate a couple of persons and print their info:
<div class='columns21' markdown='1'>
<div markdown='1'>
```csharp
class Program
{
static void Main(string[] args)
{
Person steve = new Person("Steve");
Person wendy = new Person("Wendy");
steve.PrintInfo();
wendy.PrintInfo();
}
}
```
</div>
<div markdown='1'>
![w:400px](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_3.png)
</div>
</div>
## Static methods
* Methods can also be static
* What happens when you try to call a non-static method from a static method?
```csharp
class Program
{
void PrintHelloName(string name)
{
Console.WriteLine("Hello, " + name);
}
static void Main(string[] args)
{
PrintHelloName(); // Will throw an error
}
}
```
<div class='centered'>
![w:800px](imgs/10%20Static%20Members%2C%20Methods%20and%20Classes_4.png)
</div>
## Static classes
* Whole classes can also be static
* Static classes cannot be instantiated, and all its members have to be static as well
```csharp
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
<!--_class: "exercise invert" -->
* Create a class `Message` that has two `static` properties `int TotalMessages` and `string LastMessage`, and a *__non-static__* property `string MessageText`.
* Add a constructor that takes a `string message` as a parameter, increases `TotalMessages` by one and sets the value of `LastMessage` to `message`.
* Create a main loop that keeps asking the user for a new message. A new `Message` instance is then created with the user input message as an argument:
```csharp
Message newMessage = new Message(message);
```
* `newMessage` is then added to a list `allMessages`.
* Finally, the static values `Message.TotalMessages` and `Message.LastMessage` are printed.

@ -1,233 +0,0 @@
# 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

File diff suppressed because one or more lines are too long

@ -0,0 +1,449 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: N. Delegates and events
---
# Delegates and events
<!-- headingDivider: 5 -->
<!-- class: invert -->
## Overview
* Delegates
* Multicast Delegates
* Anonymous Methods
* Events
## Delegates
* [Delegates](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/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:
```csharp
delegate returnType DelegateName(parameters);
```
* Example:
```csharp
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:
```csharp
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:
<div class='columns21' markdown='1'>
<div markdown='1'>
```csharp
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");
}
```
</div>
<div markdown='1'>
![](imgs/11%20Delegates%20and%20Events_1.png)
</div>
</div>
### Removing methods
* Methods can be removed from the delegate with the `-` operator:
```csharp
delegate void PrintDelegate(string output);
static void Main(string[] args)
{
...
print -= PrintInLower;
print("AaaBbbCcc"); // Outputs "AAABBBCCC"
...
}
```
### Delegates: An 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:
```csharp
public class DelegateTest
{
public DelegateTest(PrintDelegate printDelegate)
{
printDelegate("This Method Was Called From Another Class!");
}
}
```
---
<div class='columns21' markdown='1'>
<div markdown='1'>
```csharp
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);
```
</div>
<div markdown='1'>
Now we can create a new DelegateTest object and pass the delegate to the object constructor:
![](imgs/11%20Delegates%20and%20Events_2.png)
</div>
</div>
### Anonymous methods
* Delegates can be initialized anonymously (without a specified name)
* Anonymous method in variable declaration:
```csharp
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 that does nothing:
```csharp
delegate void SomeDelegate();
class Program
{
static void Main(string[] args)
{
// Initialize an empty delegate, add method later...
SomeDelegate myDelegate = new SomeDelegate(delegate { });
}
}
```
## Events
### The problem
<div class='columns' markdown='1'>
<div markdown='1'>
```csharp
class Game
{
Sound gameOverSound;
Window gameOverScreen;
void OnGameOver()
{
gameOverSound.Play(); // plays some sound
gameOverScreen.Show(); // shows a screen
}
}
...
class Program
{
static void Main()
{
var game = new Game();
// somewhere in the game logic...
// game.OnGameOver();
}
}
```
</div>
<div markdown='1'>
* Consider a game engine with three classes, `Sound`, `Window` and `Game`.
* If implemented like this, the `Game` class has to know about the `Sound` and `Window` classes
* $\Rightarrow$ `Game` is ***tightly coupled***, and thus ***dependent*** on the `Sound` and `Window` classes
* Changes in either of the classes could break the code!
</div>
</div>
### The solution: Events
* A solution to this problem is the [Publisher-subscriber pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
* In C#, this pattern is implemented with the [`event` keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/event?redirectedfrom=MSDN)
* Events are ***signals*** that are raised by a *__Publisher__* and received by a *__Subscriber__*
* The publisher does not know or care who, if anyone, receives the signal
* Changes in the subscriber classes do not affect the publisher
* In C#, events are multicast delegates
* When an object triggers an event, the event invokes ***event handlers***
* Event handlers are delegate instances added to the event
### Raising events
* Events consist of two elements:
* A delegate that identifies the method that provides the response to the event
* In the simplest case, we can use the built-in [`EventHandler`](https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler?view=net-9.0) delegate
* An optional class to hold event data if the event provides data.
```csharp
public class Publisher
{
public event EventHandler SampleEvent;
// Wrap the event in a protected virtual method
// to enable derived classes to raise the event.
protected virtual void OnSampleEvent()
{
// Raise the event in a thread-safe manner using the ?. operator.
SampleEvent?.Invoke(this);
}
}
```
### Raising the event
Events can only be invoked (i.e., raised) from within the class (or derived classes) or struct where they're declared (the publisher class)
<div class='columns' markdown='1'>
<div markdown='1'>
```csharp
public class Publisher
{
public event EventHandler SampleEvent;
protected virtual void OnSampleEvent()
{
SampleEvent?.Invoke(this);
}
}
```
</div>
<div markdown='1'>
```csharp
class Program
{
static void Main()
{
var pub = new Publisher();
pub.OnSampleEvent(); // ✅ Works fine
// pub.SampleEvent(); // ❌ Not allowed!
}
}
```
</div>
</div>
### Adding subscribers to the event
* Now that we know how to raise the event, we can add subscribers to it
* i.e., functions that get called when the event is raised
<div class='columns' markdown='1'>
<div markdown='1'>
```csharp
public class Publisher
{
public event EventHandler SampleEvent;
protected virtual void OnSampleEvent()
{
SampleEvent?.Invoke(this);
}
}
```
</div>
<div markdown='1'>
```csharp {7-8}
class Program
{
static void Main()
{
var pub = new Publisher();
pub.SampleEvent +=
() => Console.WriteLine("Sample event!");
pub.OnSampleEvent();
}
}
```
</div>
</div>
### Custom event handler
* We can define the delegate ourselves, for example if we want to send some data to the event.
```csharp
public class Publisher
{
public delegate void SampleEventHandler(object sender);
// Declare the event.
public event SampleEventHandler SampleEvent;
protected virtual void OnSampleEvent()
{
SampleEvent?.Invoke(this);
}
}
```
### Event arguments
* Finally, we can send arguments to the event like this:
```csharp
public class SampleEventArgs
{
public SampleEventArgs(string text) { Text = text; }
public string Text { get; } // readonly
}
public class Publisher
{
public delegate void SampleEventHandler(object sender, SampleEventArgs e);
public event SampleEventHandler SampleEvent;
protected virtual void RaiseSampleEvent()
{
SampleEvent?.Invoke(this, new SampleEventArgs("Hello"));
}
}
```
### "Fixing" the Game Over example
<div class='columns' markdown='1'>
<div markdown='1'>
```csharp
public delegate void GameOverHandler();
class Game
{
public event GameOverHandler GameOver;
protected virtual void OnGameOver()
{
GameOver?.Invoke(this);
}
}
...
class Program
{
static void Main()
{
var game = new Game();
Sound gameOverSound;
Window gameOverScreen;
game.GameOver += gameOverSound.Play;
game.GameOver += gameOverScreen.Show;
}
}
```
</div>
<div markdown='1'>
1) Declare an event handler delegate (`GameOverHandler`)
2) Declare an instance of the handler with the `event` keyword (`GameOVer`)
3) Declare a virtual method that invokes the event
4) Add methods that subscribe to the event
</div>
</div>
## Exercise 1: A rudimentary event system
<!--_class: "exercise invert" -->
Create a console application for controlling a plant treatment system with three methods that print the following outputs:
| Method | Output |
| :-- | :-- |
| `void ReleaseWater()` | `Releasing water...` |
| `void ReleaseFertilizer()` | `Releasing fertilizer...` |
| `void IncreaseTemperature()` | `Increasing temperature...` |
* All methods are off by default. Create a main loop where the user can...
* ...type the name of the method to switch each method on (add it to the delegate)
* ...type `run` to execute all the methods that are on
---
<!--_class: "exercise invert" -->
* ***Hint:*** you can just use switch-case for defining which method should be added to the delegate
* Here's an example console input & output:
![](imgs/11%20Delegates%20and%20Events_3.png)

@ -1,290 +0,0 @@
# Delegates and Events
![](imgs/11%20Delegates%20and%20Events_0.png)
---
# Overview
Delegates
Multicast Delegates
Anonymous Methods
Events
# Delegates
* [Delegates](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/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)

File diff suppressed because one or more lines are too long

@ -217,15 +217,15 @@ The following reads the first 20 characters of a file and prints them to the con
```csharp
string path = @"C:\Users\Public\TestFolder\TestFile.txt";
int nOfBytesToPrint = 20;
byte[] byteArray = new byte[nOfBytesToPrint];
int numberOfBytesToPrint = 20;
byte[] byteArray = new byte[numberOfBytesToPrint];
if (!File.Exists(path))
Console.WriteLine($"The file {path} does not exist.");
else
using (FileStream fs = File.OpenRead(path))
{
fs.Read(byteArray, 0, nOfBytesToPrint);
fs.Read(byteArray, 0, numberOfBytesToPrint);
};
// No need to close the file since it was handled inside of a using block

@ -47,32 +47,30 @@ class Program
### Multiple type parameters
Generic classes can receive multiple types as parameters:
```csharp
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)
* Generic classes can receive multiple types as parameters:
```csharp
class CustomContainer<T1, T2, T3>
{
CustomContainer<int, string, DateTime> container
= new CustomContainer<int, string, DateTime>();
container.First = 10;
container.Second = "Testing.";
container.Third = DateTime.Now;
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;
}
}
```
### Creating a generic Method
```csharp
void GenericMethodExample<T>(T value)
{
Console.WriteLine
@ -83,7 +81,7 @@ GenericMethodExample<string>("ABC");
![](imgs/13%20Generics%2C%20IEnumerable%20and%20LINQ_2.png)
* ***Note:*** You could name the generic type as anything, e.g. `<GenericType>`. It is named `<T>` by convention.
* ***Note:*** You could name the generic type as anything, e.g. `<GenericType>`. It is named `<T>` here by convention.
## Exercise 1: Initializing a populated list
<!-- _class: exercise -->

@ -250,7 +250,7 @@ class Program
{
int waitTime = 5000;
await Task.Delay(waitTime);
// Replace this with your time consuming async functionality
// Replace above with some time-consuming async function
return new string(
$"The task took {waitTime / 1000} seconds to finish."
);
@ -260,7 +260,7 @@ class Program
Console.WriteLine("Starting operation...");
Task<string> resultTask = GetResultAsync();
Console.WriteLine("Operation has been started.");
Console.WriteLine("In the meantime, tell me something nice: ");
Console.WriteLine("In the meantime, say something nice:");
string somethingNice = Console.ReadLine();
resultTask.Wait(); // Wait for the task to complete
Console.WriteLine(resultTask.Result);
@ -280,5 +280,5 @@ class Program
## Exercise 3: Asynchronous Loading
<!-- _class: exercise -->
Re-create the exercise 2, but instead of using separate threads for "loading the data", use an asynchronous method `LoadDataAsync()`
Redo exercise 2, but instead of using separate threads for "loading the data", use an asynchronous method `LoadDataAsync()`.

File diff suppressed because one or more lines are too long

@ -23,7 +23,7 @@ title: 15. Design Patterns in C#
* In most cases, it makes no sense to create an instance of a class every time its 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 [lecture 10](10.%20Static%20Members,%20Methods%20and%20Classes.md#StaticClasses), static classes can only have static members
* As stated in [lecture 10](10-static-members-methods-and-classes#StaticClasses), 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/)
@ -69,7 +69,6 @@ A singleton implementation could look something like this:
<div markdown='1'>
```csharp
class Program
{
static void Main(string[] args)
@ -123,11 +122,9 @@ public class HomeController : Controller
## 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
* Thus, 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/)
```csharp
public void ConfigureServices(IServiceCollection services)
{

File diff suppressed because one or more lines are too long

@ -0,0 +1,307 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: 8. Inheritance & Abstract Classes
---
# Inheritance & Abstract Classes
<!-- headingDivider: 5 -->
<!-- class: invert -->
## Overview
* Inheritance
* Abstract classes
* Enums
* OOP
## 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
### An inheritance example
<center>
| `class Animal` | `class Dog : Animal` | `class Cat : Animal` |
|:--------------:|:--------------------:|:--------------------:|
| `Eat()` | `Bark()` | `Meow()` |
| `Sleep()` | | |
</center>
<br>
<div class='columns111' markdown='1'>
<div markdown='1'>
* Animal can eat
* Animal can sleep
</div>
<div markdown='1'>
* Dog can eat
* Dog can sleep
* Dog can bark
</div>
<div markdown='1'>
* Cat can eat
* Cat can sleep
* Cat can meow
</div>
</div>
### Inheritance: An example implementation
<div class='columns' markdown='1'>
<div markdown='1'>
```csharp
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!"); }
}
```
</div>
<div markdown='1'>
```csharp
class Program
{
static void Main(string[] args)
{
Dog pluto = new Dog();
pluto.Eat(); // Outputs "Eating..."
pluto.Bark(); // Outputs "Bark!"
}
}
```
</div>
</div>
### Inheritance continued
* All the objects deriving from the same base class can be referenced with the base class name:
```csharp
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:
```csharp
plutoAnimal.Eat(); // Outputs "Eating..."
plutoAnimal.Bark(); // Error
```
* An object of base class type can be *__cast__* into the child class type:
```csharp
Dog pluto = (Dog)plutoAnimal;
pluto.Bark(); // Outputs "Bark!"
```
## Abstract Classes
* In some cases you want the base class to be made [abstract](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/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:
```csharp
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:
```csharp
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:
```csharp
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
}
}
```
## Exercise 1. Animal farm
<!--_class: "exercise invert" -->
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`
2) Give `Dog`, `Cat` and `Pig` some fields and/or methods specific to that animal
3) Create a few instances of `Dog`, `Cat` and `Pig`, and add them to a list `allAnimals`
4) Loop through `allAnimals` with the `foreach` statement, and call the `Greet()` method of each animal
## Enums
* [Enum](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) (short for enumeration) is a data type for holding a set of constant (immutable) names
* Enums can be useful when you have a given number of ***states*** that are predefined
* For example, weekdays
* Another example is an extension of boolean with three states `True`, `False` and `Maybe`
### Creating enums
* Create an `enum` type with the enum keyword:
```csharp
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
```
* Then, create a new variable with the type `Season` and assign one of the enum type's values to it:
```csharp
Season currentSeason = Season.Spring;
```
### Enums: An example
<div class='columns12' markdown='1'>
<div markdown='1'>
In this example, an enum is used to keep track of the state of the program.
```csharp
enum ProgramState
{
Login,
Menu,
Exit
}
```
</div>
<div markdown='1'>
```csharp
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;
}
}
}
```
</div>
</div>
## Extra: Object Oriented Programming
<!-- _class: "extra invert" -->
* 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
* Polymorphism
### Encapsulation
<!-- _class: "extra invert" -->
* Earlier we created classes that hold properties and methods that 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 is made available **_only when it is needed_** by instantiating an object of the class
### Inheritance
<!-- _class: "extra invert" -->
* As shown earlier, inheritance allows you to write some functionality once, and then create separate classes which all share that same functionality
* This removes the need to rewrite the same code inside every class
### Abstraction
<!-- _class: "extra invert" -->
* 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
* Example: The user of a microwave doesn't have to know about the complicated circuitry inside of the microwave. Only the buttons are revealed
### Polymorphism
<!-- _class: "extra invert" -->
* This concept becomes more clear after we have covered interfaces in the next lecture
* 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

@ -1,302 +0,0 @@
# 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

File diff suppressed because one or more lines are too long

@ -0,0 +1,248 @@
---
marp: true
paginate: true
math: mathjax
theme: buutti
title: 9. Interfaces
---
# Interfaces
<!-- headingDivider: 5 -->
<!-- class: invert -->
## 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 defined in the interface
* As with [abstract classes](8-inheritance-and-abstract-classes.md#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:
```csharp
interface IUser
{
int Id { get; set; }
string Name { get; set; }
void GetUserStatistics();
}
```
* [Interface names should begin](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces) with the capital letter `I` 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:
```csharp
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 next
---
```csharp
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 does not dictate **_how_** the methods are implemented, those just need to be implemented
* ***Note:*** To quickly implement the interface, click the IUser interface name and click _💡 > 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:
```csharp
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:
```csharp
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?
### Example 1
<center>
| `class Dog` | `class Human` | `class Bear` |
|:------------|:----------------|:--------------|
| `Eat()` | `Eat()` | `Eat()` |
| `Sleep()` | `Sleep()` | `Sleep()` |
| `WagTail()` | `Contemplate()` | `Hibernate()` |
</center>
* All classes could inherit from a base class `Animal`, which has methods `Eat()` and `Sleep()`
* The question is, should the base class be abstract?
* Depends on your program: do you ever need an object that can ***only*** `Eat()` and `Sleep()`?
### Example 2
<center>
| `class Tree` | `class Human` | `class Car` |
|:--------------------|:--------------|:------------|
| `Grow()` | `Grow()` | `Explode()` |
| `Photosynthesize()` | `Move()` | `Move()` |
</center>
* 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: An 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
---
<div class='columns12' markdown='1'>
<div markdown='1'>
```csharp
interface IMovable
{
void Move();
}
interface ICarryable
{
void Carry();
}
```
</div>
<div markdown='1'>
```csharp
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");
}
}
```
</div>
</div>
---
<div class='columns21' markdown='1'>
<div markdown='1'>
```csharp
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();
}
}
```
</div>
<div markdown='1'>
![](imgs/9%20Interfaces_1.png)
</div>
</div>
## Exercise 1: A web of relations
<!--_class: "exercise invert" -->
Create a console application that has an interface `IInfo` and two classes `Product` and `Category` that both implement `IInfo`.
1) Inside `IInfo`, declare a property `InfoText` and a method `PrintInfo`
2) Implement both the property and method in `Product` and `Category`
3) Initialize a couple of products and categories, with info texts of your choice
4) Create a list of type `IInfo`, and add the products and categories to it
5) 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
<!--_class: "exercise invert" -->
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.
1) Start by creating 4 classes: `Shape`, `Square`, `Triangle`, and `Circle`. `Square`, `Triangle` and `Circle` inherit from `Shape`, which implements the `IComparable<Shape>` interface.
2) 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`.
---
<!--_class: "exercise invert" -->
3) `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.
4) 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.
5) Print the areas in the sorted array with a `foreach` loop. They should be printed in an increasing order.

@ -1,270 +0,0 @@
# 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.

@ -2,8 +2,13 @@
Material completion denoted with 🌑🌘🌗🌖🌕 .
| # | Lecture | Materials | Exercises |
| ---: | ------------------------------------- | --------: | --------: |
| 13 | [Generics, IEnumberable and LINQ](13.%20Generics,%20IEnumerable%20and%20LINQ.md) | 🌕 | 🌕 |
| 14 | [Exceptions, Threads and Tasks](14.%20Exceptions,%20Threads%20and%20Tasks.md) | 🌕 | 🌕 |
| 15 | [Design Patterns in C#](15.%20Design%20Patterns%20in%20C#.md) | 🌗 | 🌑 |
| # | Lecture | Materials | Exercises |
|---:|------------------------------------------------------------------------|----------:|----------:|
| 8 | [Inheritance and Abstract Classes](8-inheritance-and-abstract-classes.md) | 🌕 | 🌕 |
| 9 | [Interfaces](9-interfaces.md) | 🌕 | 🌕 |
| 10 | [Static Members, Methods, and Classes](10-static-members-methods-and-classes.md) | 🌕 | 🌕 |
| 11 | [Delegates and Events](11-delegates-and-events.md) | 🌕 | 🌗 |
| 12 | [Files and Streams](12-files-and-streams.md) | 🌕 | 🌕 |
| 13 | [Generics, IEnumberable and LINQ](13-generics-ienumerable-and-linq.md) | 🌕 | 🌕 |
| 14 | [Exceptions, Threads and Tasks](14-exceptions-threads-and-tasks.md) | 🌕 | 🌕 |
| 15 | [Design Patterns in C#](15-design-patterns-in-csharp.md) | 🌗 | 🌑 |

Loading…
Cancel
Save