parent
76b49a6af8
commit
24ec8f9349
File diff suppressed because one or more lines are too long
@ -1,233 +1,198 @@
|
|||||||
# Static Members, Methods and Classes
|
---
|
||||||
|
marp: true
|
||||||

|
paginate: true
|
||||||
|
math: mathjax
|
||||||
|
theme: buutti
|
||||||
|
title: 10. Static Members, Methods and Classes
|
||||||
---
|
---
|
||||||
|
|
||||||
# Static Members
|
# Static Members, Methods and Classes
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
__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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
# 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();
|
<!-- 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
wendy.PrintInfo();
|
---
|
||||||
|
|
||||||
}
|
* 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'>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</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'>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
}
|
---
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
# Static Methods
|
|
||||||
|
|
||||||
Methods can also be static
|
* Now let's instantiate a couple of persons and print their info:
|
||||||
|
|
||||||
What happens when you try to call a non-static method from a static method?
|
<div class='columns21' markdown='1'>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
|
```csharp
|
||||||
class Program
|
class Program
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
void PrintHelloName(string name)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
Console.WriteLine("Hello, " + name);
|
{
|
||||||
|
Person steve = new Person("Steve");
|
||||||
}
|
Person wendy = new Person("Wendy");
|
||||||
|
steve.PrintInfo();
|
||||||
static void Main(string[] args)
|
wendy.PrintInfo();
|
||||||
|
}
|
||||||
{
|
}
|
||||||
|
```
|
||||||
PrintHelloName(); // Will throw an error
|
|
||||||
|
</div>
|
||||||
}
|
<div markdown='1'>
|
||||||
|
|
||||||
}
|

|
||||||
|
|
||||||

|
</div>
|
||||||
|
</div>
|
||||||
---
|
|
||||||
|
## Static methods
|
||||||
This is why until this point all example methods have been inside of the main function
|
|
||||||
|
* Methods can also be static
|
||||||
# Static Classes
|
* What happens when you try to call a non-static method from a static method?
|
||||||
|
```csharp
|
||||||
* Classes can also be made static
|
class Program
|
||||||
* Static classes cannot be instantiated
|
{
|
||||||
* All members of a static class also have to be static
|
void PrintHelloName(string name)
|
||||||
* static class Styling
|
{
|
||||||
* {
|
Console.WriteLine("Hello, " + name);
|
||||||
* public static string fontFamily = "Verdana";
|
}
|
||||||
* public static float fontSize = 12.5f;
|
static void Main(string[] args)
|
||||||
* }
|
{
|
||||||
* class Program
|
PrintHelloName(); // Will throw an error
|
||||||
* {
|
}
|
||||||
* static void Main(string[] args)
|
}
|
||||||
* {
|
```
|
||||||
* Console.WriteLine
|
|
||||||
* ("Using font " + Styling.fontFamily + " " + Styling.fontSize + "px");
|
<div class='centered'>
|
||||||
* // Outputs "Using font Verdana 12.5px"
|
|
||||||
* Styling = new Styling(); // Results in an error
|

|
||||||
* }
|
|
||||||
* }
|
</div>
|
||||||
|
|
||||||
# Exercise 1
|
## Static classes
|
||||||
|
|
||||||
Create a class Message which has two __static __ properties int TotalMessages and string LastMessage, and a __non-static __ property string MessageText.
|
* Whole classes can also be static
|
||||||
|
* Static classes cannot be instantiated, and all its members have to be static as well
|
||||||
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
|
```csharp
|
||||||
|
static class Styling
|
||||||
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:
|
{
|
||||||
|
public static string fontFamily = "Verdana";
|
||||||
Message newMessage = new Message(message);
|
public static float fontSize = 12.5f;
|
||||||
|
}
|
||||||
newMessage is then added to a list of messages, allMessages
|
class Program
|
||||||
|
{
|
||||||
Finally the static values Message.TotalMessages and Message.LastMessage are printed
|
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.
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,302 +1,307 @@
|
|||||||
# Inheritance & Abstract Classes
|
---
|
||||||
|
marp: true
|
||||||

|
paginate: true
|
||||||
|
math: mathjax
|
||||||
|
theme: buutti
|
||||||
|
title: 8. Inheritance & Abstract Classes
|
||||||
---
|
---
|
||||||
|
|
||||||
# Overview
|
# Inheritance & Abstract Classes
|
||||||
|
|
||||||
Inheritance
|
|
||||||
|
|
||||||
Abstract Classes
|
|
||||||
|
|
||||||
Enums
|
<!-- headingDivider: 5 -->
|
||||||
|
<!-- class: invert -->
|
||||||
|
|
||||||
# Inheritance
|
## Overview
|
||||||
|
|
||||||
Classes can be made to inherit functionality of some other class
|
* Inheritance
|
||||||
|
* Abstract classes
|
||||||
|
* Enums
|
||||||
|
* OOP
|
||||||
|
|
||||||
If class B inherits class A, all of the (public) functionality in class A is also available in class B
|
## Inheritance
|
||||||
|
|
||||||
A is called the __base class__ (or parent class) and B is called the __derived class __ (or child class)
|
* 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
|
||||||
|
|
||||||
Use the " __:"__ symbol to make a class inherit from another
|
### An inheritance example
|
||||||
|
|
||||||
Try to understand the following example:
|
<center>
|
||||||
|
|
||||||
| class Animal |
|
| `class Animal` | `class Dog : Animal` | `class Cat : Animal` |
|
||||||
| :-: |
|
|:--------------:|:--------------------:|:--------------------:|
|
||||||
| -Eat()-Sleep() |
|
| `Eat()` | `Bark()` | `Meow()` |
|
||||||
|
| `Sleep()` | | |
|
||||||
|
|
||||||
| class Dog : Animal |
|
</center>
|
||||||
| :-: |
|
|
||||||
| -Bark() |
|
|
||||||
|
|
||||||
| class Cat : Animal |
|
<br>
|
||||||
| :-: |
|
|
||||||
| -Meow() |
|
|
||||||
|
|
||||||
Animal can eat
|
<div class='columns111' markdown='1'>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
Animal can sleep
|
* Animal can eat
|
||||||
|
* Animal can sleep
|
||||||
|
|
||||||
Dog can eat
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
Dog can sleep
|
* Dog can eat
|
||||||
|
* Dog can sleep
|
||||||
|
* Dog can bark
|
||||||
|
|
||||||
Dog can bark
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
Cat can eat
|
* Cat can eat
|
||||||
|
* Cat can sleep
|
||||||
|
* Cat can meow
|
||||||
|
|
||||||
Cat can sleep
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
Cat can meow
|
### Inheritance: An example implementation
|
||||||
|
|
||||||
# Inheritance - Example
|
<div class='columns' markdown='1'>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
|
```csharp
|
||||||
class Animal
|
class Animal
|
||||||
|
|
||||||
{
|
{
|
||||||
|
public void Eat()
|
||||||
public void Eat() { Console.WriteLine("Eating..."); }
|
{ Console.WriteLine("Eating..."); }
|
||||||
|
public void Sleep()
|
||||||
public void Sleep() { Console.WriteLine("Sleeping..."); }
|
{ Console.WriteLine("Sleeping..."); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Cat : Animal
|
class Cat : Animal
|
||||||
|
|
||||||
{
|
{
|
||||||
|
public void Meow()
|
||||||
public void Meow() { Console.WriteLine("Meow!"); }
|
{ Console.WriteLine("Meow!"); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dog : Animal
|
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 Bark()
|
||||||
public void Eat() { Console.WriteLine("Eating..."); }
|
{ Console.WriteLine("Bark!"); }
|
||||||
|
|
||||||
public void Sleep() { Console.WriteLine("Sleeping..."); }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
class Pig : Animal
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
{
|
|
||||||
|
|
||||||
public void Squeal() { Console.WriteLine("Squeee!"); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
```csharp
|
||||||
class Program
|
class Program
|
||||||
|
|
||||||
{
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
static void Main(string[] args)
|
{
|
||||||
|
Dog pluto = new Dog();
|
||||||
{
|
pluto.Eat(); // Outputs "Eating..."
|
||||||
|
pluto.Bark(); // Outputs "Bark!"
|
||||||
Pig pig = new Pig();
|
}
|
||||||
|
|
||||||
pig.Sleep(); // Outputs "Sleeping..."
|
|
||||||
|
|
||||||
pig.Squeal(); // Outputs "Squeee!"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
}
|
|
||||||
|
</div>
|
||||||
If you know you only need the functionality of the abstract class, instantiate the new class as a type of abstract class:
|
</div>
|
||||||
|
|
||||||
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 }}
|
### 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This is called abstraction, which is one of the key concepts of OOP
|
* Instead, the methods are accessible through a derived class:
|
||||||
|
```csharp
|
||||||
# Exercise 1
|
abstract class Animal
|
||||||
|
{
|
||||||
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
|
public void Eat() { Console.WriteLine("Eating..."); }
|
||||||
|
public void Sleep() { Console.WriteLine("Sleeping..."); }
|
||||||
Give Dog, Cat and Pig some fields and/or methods specific to that animal
|
}
|
||||||
|
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!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
|
* 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
|
enum ProgramState
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Login,
|
||||||
Login,
|
Menu,
|
||||||
|
Exit
|
||||||
Menu,
|
|
||||||
|
|
||||||
Exit
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
static void Main(string[] args)
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
{
|
|
||||||
|
|
||||||
ProgramState currentState = ProgramState.Login;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
switch (currentState)
|
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
ProgramState currentState = ProgramState.Login;
|
||||||
case ProgramState.Login:
|
while (true)
|
||||||
|
{
|
||||||
// Switch current state to Menu after logging in
|
switch (currentState)
|
||||||
|
{
|
||||||
break;
|
case ProgramState.Login:
|
||||||
|
// Switch current state to Menu after logging in
|
||||||
case ProgramState.Menu:
|
break;
|
||||||
|
case ProgramState.Menu:
|
||||||
// Switch current state to Exit if user exits
|
// Switch current state to Exit if user exits
|
||||||
|
break;
|
||||||
break;
|
case ProgramState.Exit:
|
||||||
|
// Exit the program with an exit message
|
||||||
case ProgramState.Exit:
|
break;
|
||||||
|
}
|
||||||
// Exit the program with an exit message
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
# Going Further: Object Oriented Programming
|
## 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 instances that are created with the `new` keyword are ***objects***.
|
||||||
* The key concepts of OOP are
|
* 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
|
* Encapsulation
|
||||||
* Inheritance
|
* Inheritance
|
||||||
* Abstraction, and
|
* Abstraction
|
||||||
* Polymorphism
|
* Polymorphism
|
||||||
|
|
||||||
# OOP: Encapsulation
|
### Encapsulation
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
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
|
* 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
|
||||||
|
|
||||||
Instead, reveal only the parts that the user (you, a workmate, etc) actually need, with abstraction
|
### Inheritance
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
|
|
||||||
Parable: The user of a microwave doesn't have to know about the complicated circuitry inside of the microwave. Only the buttons are revealed
|
* 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
|
||||||
|
|
||||||
# OOP: Polymorphism
|
### Abstraction
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
|
|
||||||
This concept becomes more clear after we have covered interfaces
|
* 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 refers to multiple classes having the same method but with different functionality
|
### Polymorphism
|
||||||
|
<!-- _class: "extra invert" -->
|
||||||
|
|
||||||
This reduces the need for massive if-else and switch..case statements
|
* 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
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,270 +1,248 @@
|
|||||||
# Interfaces
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
marp: true
|
||||||
|
paginate: true
|
||||||
|
math: mathjax
|
||||||
|
theme: buutti
|
||||||
|
title: 9. Interfaces
|
||||||
|
---
|
||||||
|
# Interfaces
|
||||||
|
|
||||||
# Overview
|
<!-- headingDivider: 5 -->
|
||||||
|
<!-- class: invert -->
|
||||||
|
|
||||||
Interfaces
|
## Overview
|
||||||
|
|
||||||
Interfaces or Inheritance?
|
* Interfaces
|
||||||
|
* Interfaces or Inheritance?
|
||||||
|
|
||||||
# Interfaces
|
## Interfaces
|
||||||
|
|
||||||
* In addition to abstract classes, __interfaces __ are a way to achieve abstraction to your program
|
* In addition to abstract classes, *__interfaces__* are a way to achieve abstraction to your program
|
||||||
* Interfaces are classes that have __no internal functionality__
|
* Interfaces are classes that have *__no internal functionality__*
|
||||||
* Interfaces describe the methods and properties that a class has to have when implementing the interface
|
* 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
|
* 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, interfaces cannot be instantiated directly
|
* 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
|
* (It wouldn't make any sense as interfaces have no implementation)
|
||||||
* Interfaces are way more commonly used than abstract classes
|
* Interfaces are way more commonly used than abstract classes
|
||||||
|
|
||||||
# Creating an Interface
|
### Creating an interface
|
||||||
|
|
||||||
* Define an interface using the interface keyword instead of class:
|
* Define an interface using the interface keyword instead of class:
|
||||||
* interface IUser
|
```csharp
|
||||||
* {
|
interface IUser
|
||||||
* int Id { get; set; }
|
{
|
||||||
* string Name { get; set; }
|
int Id { get; set; }
|
||||||
* void GetUserStatistics();
|
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
|
```
|
||||||
|
* [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)
|
* Methods are declared without the method body (no implementation)
|
||||||
* The methods are implemented on the classes that uses the interface
|
* The methods are implemented on the classes that uses the interface
|
||||||
|
|
||||||
# Implementing an 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
|
* Implement an interface just like you would inherit a class:
|
||||||
|
```csharp
|
||||||
|
class User : IUser
|
||||||
|
{
|
||||||
|
|
||||||
Let's fix that by defining those now
|
}
|
||||||
|
```
|
||||||
|
* 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
|
||||||
|
|
||||||
# Implementing an Interface (continued)
|
---
|
||||||
|
|
||||||
|
```csharp
|
||||||
class User : IUser
|
class User : IUser
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public void GetUserStatistics()
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
// Some code here
|
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_.
|
||||||
|
|
||||||
The interface is now fully implemented and the compiler is happy
|
### Implementing multiple interfaces
|
||||||
|
|
||||||
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
|
* Unlike with inheritance, classes can implement multiple interfaces
|
||||||
* In contrast, classes can only inherit from one base class
|
* In contrast, classes can only inherit from one base class
|
||||||
* This is done by separating the interfaces with a comma:
|
* This is done by separating the interfaces with a comma:
|
||||||
* class Rock : IPickable, IThrowable, ICrushable
|
```csharp
|
||||||
* {
|
class Rock : IPickable, IThrowable, ICrushable
|
||||||
* // Code that implements IPickable, IThrowable and 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
|
### Why use interfaces?
|
||||||
|
|
||||||
Consider the following example:
|
* 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
|
||||||
public void DeleteData(IDeletable data)
|
* Consider the following example:
|
||||||
|
```csharp
|
||||||
{
|
public void DeleteData(IDeletable data)
|
||||||
|
{
|
||||||
data.Delete();
|
data.Delete();
|
||||||
|
}
|
||||||
}
|
```
|
||||||
|
* The above method accepts **_any_** type of object that implements `IDeletable`, regardless of other functionality
|
||||||
|
|
||||||
The above method accepts _any _ type of object that implements IDeletable, regardless of other functionality
|
## Interface or Inheritance?
|
||||||
|
|
||||||
# Interface or Inheritance?
|
### Example 1
|
||||||
|
|
||||||
| class Dog |
|
<center>
|
||||||
| :-: |
|
|
||||||
| -Eat()-Sleep()-WagTail() |
|
|
||||||
|
|
||||||
| class Human |
|
| `class Dog` | `class Human` | `class Bear` |
|
||||||
| :-: |
|
|:------------|:----------------|:--------------|
|
||||||
| -Eat()-Sleep()-Contemplate() |
|
| `Eat()` | `Eat()` | `Eat()` |
|
||||||
|
| `Sleep()` | `Sleep()` | `Sleep()` |
|
||||||
|
| `WagTail()` | `Contemplate()` | `Hibernate()` |
|
||||||
|
|
||||||
| class Bear |
|
</center>
|
||||||
| :-: |
|
|
||||||
| -Eat()-Sleep()-Hibernate() |
|
|
||||||
|
|
||||||
All classes could inherit from a base class Animal, which has methods Eat() and Sleep()
|
* 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()`?
|
||||||
|
|
||||||
Should the base class be abstract? Depends on your program: do you ever need an object that can only Eat() and Sleep()?
|
### Example 2
|
||||||
|
|
||||||
| class Tree |
|
<center>
|
||||||
| :-: |
|
|
||||||
| -Grow()-Photosynthesize() |
|
|
||||||
|
|
||||||
| class Human |
|
| `class Tree` | `class Human` | `class Car` |
|
||||||
| :-: |
|
|:--------------------|:--------------|:------------|
|
||||||
| -Grow()-Move() |
|
| `Grow()` | `Grow()` | `Explode()` |
|
||||||
|
| `Photosynthesize()` | `Move()` | `Move()` |
|
||||||
|
|
||||||
| class Car |
|
</center>
|
||||||
| :-: |
|
|
||||||
| -Move()-Explode() |
|
|
||||||
|
|
||||||
It wouldn't make sense to use inheritance here, since there is no functionality that is shared between all classes
|
* 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`
|
||||||
|
|
||||||
Instead you could make two interfaces: IGrowable and IMovable
|
## Interfaces: An example
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
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
|
interface IMovable
|
||||||
|
|
||||||
{
|
{
|
||||||
|
void Move();
|
||||||
void Move();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICarryable
|
interface ICarryable
|
||||||
|
|
||||||
{
|
{
|
||||||
|
void Carry();
|
||||||
void Carry();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
class Elephant : IMovable
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
{
|
|
||||||
|
|
||||||
public void Move()
|
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Elephant : IMovable
|
||||||
{
|
{
|
||||||
|
public void Move()
|
||||||
Console.WriteLine("The elephant is moving'");
|
{
|
||||||
|
Console.WriteLine("The elephant is moving'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Cat : IMovable, ICarryable
|
class Cat : IMovable, ICarryable
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
public void Move()
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
Console.WriteLine("The cat is moving'");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Carry()
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
public void Move()
|
||||||
Console.WriteLine("You are carrying the cat");
|
{
|
||||||
|
Console.WriteLine("The cat is moving'");
|
||||||
|
}
|
||||||
|
public void Carry()
|
||||||
|
{
|
||||||
|
Console.WriteLine("You are carrying the cat");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class Rock : ICarryable
|
class Rock : ICarryable
|
||||||
|
|
||||||
{
|
{
|
||||||
|
public void Carry()
|
||||||
public void Carry()
|
{
|
||||||
|
Console.WriteLine("You are carrying the rock");
|
||||||
{
|
}
|
||||||
|
|
||||||
Console.WriteLine("You are carrying the rock");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
class Program
|
|
||||||
|
|
||||||
{
|
---
|
||||||
|
|
||||||
static void Main(string[] args)
|
<div class='columns21' markdown='1'>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Program
|
||||||
{
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
Elephant elephant = new Elephant();
|
{
|
||||||
|
Elephant elephant = new Elephant();
|
||||||
Cat cat = new Cat();
|
Cat cat = new Cat();
|
||||||
|
Rock rock = new Rock();
|
||||||
Rock rock = new Rock();
|
|
||||||
|
List<IMovable> movables =
|
||||||
List<IMovable> movables = new List<IMovable>{ elephant, cat };
|
new List<IMovable>{ elephant, cat };
|
||||||
|
List<ICarryable> carryables =
|
||||||
List<ICarryable> carryables = new List<ICarryable>{ cat, rock };
|
new List<ICarryable>{ cat, rock };
|
||||||
|
|
||||||
foreach (IMovable movable in movables)
|
foreach (IMovable movable in movables)
|
||||||
|
movable.Move();
|
||||||
movable.Move();
|
|
||||||
|
foreach (ICarryable carryable in carryables)
|
||||||
foreach (ICarryable carryable in carryables)
|
carryable.Carry();
|
||||||
|
}
|
||||||
carryable.Carry();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
}
|
</div>
|
||||||
|
<div markdown='1'>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
# Exercise 1: A Web of Relations
|
</div>
|
||||||
|
</div>
|
||||||
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
|
## Exercise 1: A web of relations
|
||||||
|
<!--_class: "exercise invert" -->
|
||||||
|
|
||||||
Create a list of type IInfo, and add the products and categories to it
|
Create a console application that has an interface `IInfo` and two classes `Product` and `Category` that both implement `IInfo`.
|
||||||
|
|
||||||
Create a main loop, where each time the user presses enter, all the info texts inside the list are printed
|
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
|
## 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.
|
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.
|
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`.
|
||||||
|
|
||||||
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" -->
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue