From 88c8c953c67e92d13882d7929c75f8108482e71b Mon Sep 17 00:00:00 2001 From: borb Date: Thu, 26 Jun 2025 15:55:37 +0300 Subject: [PATCH] finish lecture 11, fix theme not being applied in cli html conversion - update readme --- .vscode/settings.json | 2 +- 11-delegates-and-events-slides.html | 491 ++++++++++++++++++++++ 11-delegates-and-events.md | 617 +++++++++++++++++----------- README.md | 1 + 4 files changed, 881 insertions(+), 230 deletions(-) create mode 100644 11-delegates-and-events-slides.html diff --git a/.vscode/settings.json b/.vscode/settings.json index b55f5c4..89ea4d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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 }, diff --git a/11-delegates-and-events-slides.html b/11-delegates-and-events-slides.html new file mode 100644 index 0000000..d6fe970 --- /dev/null +++ b/11-delegates-and-events-slides.html @@ -0,0 +1,491 @@ +N. Delegates and events
+

Delegates and events

+
+
+

Overview

+
    +
  • Delegates +
      +
    • Multicast Delegates
    • +
    • Anonymous Methods
    • +
    +
  • +
  • Events
  • +
+
+
+

Delegates

+
    +
  • Delegates are reference type variables that hold a reference to a method or multiple methods +
      +
    • Class objects hold a reference to a class instance, delegate objects hold a reference to a method / methods
    • +
    +
  • +
  • Similar to function pointers in C and C++, or how any function in JavaScript works
  • +
  • Allows for methods to be passed as variables, useful for creating, for example, events
  • +
+
+
+

Creating a delegate

+
    +
  • +

    Declare a delegate using the following syntax:

    +
    delegate returnType DelegateName(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");
+}
+
+
+
+

+
+
+
+
+

Removing methods

+
    +
  • 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: 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:
    public class DelegateTest
    +{
    +  public DelegateTest(PrintDelegate printDelegate)
    +  {
    +    printDelegate("This Method Was Called From Another Class!");
    +  }
    +}
    +
    +
  • +
+
+
+
+
+
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);
+
+
+
+

Now we can create a new DelegateTest object and pass the delegate to the object constructor:

+

+
+
+
+
+

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 that 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

+
+
+

The problem

+
+
+
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();
+  }
+}
+
+
+
+
    +
  • 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
  • +
  • Game is tightly coupled, and thus dependent on the Sound and Window classes
  • +
  • Changes in either of the classes could break the code!
  • +
+
+
+
+
+

The solution: Events

+
    +
  • A solution to this problem is the Publisher-subscriber pattern + +
  • +
  • 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 delegate
      • +
      +
    • +
    • An optional class to hold event data if the event provides data.
    • +
    +
    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)

+
+
+
public class Publisher
+{
+    public event EventHandler SampleEvent;
+    protected virtual void OnSampleEvent()
+    {
+        SampleEvent?.Invoke(this);
+    }
+}
+
+
+
+
class Program
+{
+  static void Main()
+  {
+    var pub = new Publisher();
+
+    pub.OnSampleEvent();  // ✅ Works fine
+    // pub.SampleEvent();    // ❌ Not allowed!
+  }
+}
+
+
+
+
+
+

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
  • +
+
+
+
public class Publisher
+{
+    public event EventHandler SampleEvent;
+    protected virtual void OnSampleEvent()
+    {
+        SampleEvent?.Invoke(this);
+    }
+}
+
+
+
+
class Program
+{
+  static void Main()
+  {
+    var pub = new Publisher();
+
+    pub.SampleEvent +=
+      () => Console.WriteLine("Sample event!");
+    
+    pub.OnSampleEvent();
+  }
+}
+
+
+
+
+
+

Custom event handler

+
    +
  • We can define the delegate ourselves, for example if we want to send some data to the event.
    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:
    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

+
+
+
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;
+  }
+}
+
+
+
+
    +
  1. Declare an event handler delegate (GameOverHandler)
  2. +
  3. Declare an instance of the handler with the event keyword (GameOVer)
  4. +
  5. Declare a virtual method that invokes the event
  6. +
  7. Add methods that subscribe to the event
  8. +
+
+
+
+
+

Exercise 1: A rudimentary event system

+ +

Create a console application for controlling a plant treatment system with three methods that print the following outputs:

+ + + + + + + + + + + + + + + + + + + + + +
MethodOutput
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
    • +
    +
  • +
+
+
+
    +
  • +

    Hint: you can just use switch-case for defining which method should be added to the delegate

    +
  • +
  • +

    Here's an example console input & output:
    +

    +
  • +
+
+
\ No newline at end of file diff --git a/11-delegates-and-events.md b/11-delegates-and-events.md index 8369c33..692ffa5 100644 --- a/11-delegates-and-events.md +++ b/11-delegates-and-events.md @@ -1,289 +1,448 @@ -# Delegates and Events - -![](imgs/11%20Delegates%20and%20Events_0.png) - +--- +marp: true +paginate: true +math: mathjax +theme: buutti +title: N. Delegates and events --- -# Overview - -Delegates +# Delegates and events -Multicast Delegates + + -Anonymous Methods +## Overview -Events +* Delegates + * Multicast Delegates + * Anonymous Methods +* Events -# Delegates +## Delegates -* __Delegates __ are reference type variables that hold a __reference to a method__ or multiple methods +* *__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 \ \(\); - -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"); - -} +### 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: +
+
+ + ```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"); + } + ``` + +
+
![](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" - -... - -} +
+
+ +### 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!"); + } + } + ``` -# 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: +
+
+```csharp void PrintInLower(string text) - { - -Console.WriteLine(text.ToLower()); - + Console.WriteLine(text.ToLower()); } - void PrintInUpper(string text) - { - -Console.WriteLine(text.ToUpper()); - + 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 +Now we can create a new DelegateTest object and pass the delegate to the object constructor: -Console.WriteLine(text); +![](imgs/11%20Delegates%20and%20Events_2.png) -}; +
+
-printCheckUpper("I'm not angry!"); // Outputs I'M NOT ANGRY! -Notice that the actual method that prints the text is not declared anywhere +### Anonymous methods -You can use an empty anonymous method to initialize a delegate which does nothing: +* 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); + }; -delegate void SomeDelegate(); + printCheckUpper("I'm not angry!"); // Outputs I'M NOT ANGRY! + ``` +* Notice that the actual method that prints the text is not declared anywhere! -class Program +--- +* 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 + +
+
+ + ```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(); + } + } + ``` +
+
+ +* 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! + +
+
+ +### 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) + +
+
+ +```csharp +public class Publisher { + public event EventHandler SampleEvent; + protected virtual void OnSampleEvent() + { + SampleEvent?.Invoke(this); + } +} +``` -static void Main(string[] args) +
+
+```csharp +class Program { + static void Main() + { + var pub = new Publisher(); -// Initialize an empty delegate, add method later... - -SomeDelegate myDelegate = new SomeDelegate(delegate { }); - + pub.OnSampleEvent(); // ✅ Works fine + // pub.SampleEvent(); // ❌ Not allowed! + } } +``` -} - -# 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) +### Adding subscribers to the event -Events are signals that are raised by a __Publisher __ and received by a __Subscriber__ +* 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 -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 +
+
+```csharp +public class Publisher { - -public event GameOver GameOverEventHandler; - -// Some game logic here... - -// ... - + public event EventHandler SampleEvent; + protected virtual void OnSampleEvent() + { + SampleEvent?.Invoke(this); + } } +``` -# 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... | +```csharp {7-8} +class Program +{ + static void Main() + { + var pub = new Publisher(); + + pub.SampleEvent += + () => Console.WriteLine("Sample event!"); + + pub.OnSampleEvent(); + } +} +``` + +
+
+ + +### 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 + +
+
+ + ```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; + } + } + ``` + +
+
+ +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 + +
+
+ +## Exercise 1: A rudimentary event system + + +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 -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) +* ***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) diff --git a/README.md b/README.md index ff39820..c032995 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Material completion denoted with 🌑🌘🌗🌖🌕 . | # | Lecture | Materials | Exercises | |---:|------------------------------------------------------------------------|----------:|----------:| +| 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) | 🌕 | 🌕 |