From delegates to events 1/2

The Publish-subscribe pattern is used by everybody is working with asp.net and similar. Unfortunately not everybody has understanding what is under the hood…. my goal is to fill clarify that in this and the following post!

The start: using delegates

You can store a single method inside an instance of a delegate type and invoke that method via the delegate, if you have no idea what this means please read this and then come back here😎

using System;
namespace Obar1.EventsInPractice
{
	public class DelegateEx
	{
		public delegate bool ComparisonHandler (int a, int b);

		/*
		  * some method defintions matching the ComparisonHandler delegate
		  */

		public bool BiggertThan (int a, int b)
		{
			return a > b;
		}
		public bool SomeComparison (int a, int b)
		{
			return a == -b;
		}

		public string DotheJob (ComparisonHandler cH, int a, int b)
		{
			return string.Format ("{2} on {0} and {1}", a, b, cH (a, b) ? "TRUE" : "FALSE");
		}

		/// <summary>
		/// The running example
		/// </summary>
		public void RunME ()
		{
			int a = 10;
			int b = 100;

			Console.WriteLine (DotheJob (BiggertThan, a, b));

			Console.WriteLine (DotheJob (SomeComparison, a, b));
			// anonymous method
			Console.WriteLine (DotheJob (delegate(int a1, int b1) { return a + b > 100; }, a, b));
		}
	}
}

This an delegate usage example, nothing special.

First step: Multicast delegates

Cool to use a method signature and pass method in functions, but what about to create a chain of delegates and invoke them all in turn… In this way you can define a so called chain of subscribers that the publisher will call when some condition will occur:

using System;
namespace Obar1.EventsInPractice
{
	/// <summary>
	/// Consider a temperature control example, where a heater and a cooler are hooked up to the same thermostat.
	/// In order for a unit to turn on and off appropriately, you notify the heater and a cooler when temperature is changed.
	/// </summary>
	public class MulticastDelegateEx
	{
		/// <summary>
		/// The Cooler will be a subscriber of the Thermostat to cool down the temperature when necessary
		/// </summary>
		class Cooler
		{
			public Cooler (float temperature)
			{
				ThresholdTemp = temperature;
			}
			public float ThresholdTemp { get; set; }

			public void OnTemperatureChanged (float newTemperature)
			{
				if (newTemperature > ThresholdTemp) {
					System.Console.Write ("Cooler: On");
				} else {
					System.Console.Write ("Cooler: Off");
				}
				System.Console.WriteLine (" at {0} (Threshold at {1})", newTemperature, ThresholdTemp);
			}
		}

		class Heater
		{
			public Heater (float temperature)
			{
				ThresholdTemp = temperature;
			}
			public float ThresholdTemp { get; set; }

			public void OnTemperatureChanged (float newTemperature)
			{
				if (newTemperature < ThresholdTemp) {
					System.Console.Write ("Heater: On");
				} else {
					System.Console.Write ("Heater: Off");
				}
				System.Console.WriteLine (" at {0} (Threshold at {1})", newTemperature, ThresholdTemp);
			}
		}

		public class Thermostat
		{
// Define the delegate data type, the subscriber has to implement a signature matching method
			public delegate void TemperatureChangeHandler (float newTemperature);
// Define the event publisher
			public TemperatureChangeHandler OnTemperatureChange {
				get { return _OnTemperatureChange; }
				set { _OnTemperatureChange = value; }
			}
			//N> this is bad, no encapsulaton at all, anybody culd call OnTemperatureChange even without changing the value of _CurrentTemperature

			private TemperatureChangeHandler _OnTemperatureChange;

			public float CurrentTemperature {
				get { return _CurrentTemperature; }
				set {
					if (value != CurrentTemperature) {
						_CurrentTemperature = value;
						if (OnTemperatureChange != null)
							// notify the subscribers of the change, not the OnTemperatureChange can be null or a chain of subscribers
							OnTemperatureChange (value);

					//N> here it would be necessary to catch any possible expections thrown...
					}
				}
			}
			private float _CurrentTemperature;

		}
		public void RunME ()
		{
			// setup for the temperatures
			Thermostat thermostat = new Thermostat ();
			Heater heater = new Heater (20);
			Cooler cooler = new Cooler (30);
			int[] temperetures = { 15, 25, 35 };

			// add the subscribers
			thermostat.OnTemperatureChange += heater.OnTemperatureChanged;
			thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;

			// temperature changes
			foreach (int t in temperetures)
				thermostat.CurrentTemperature = t;

		}
	}
}

Some considerations at this point

The example is very limited in the implementation (to help to focus on the core…), for example veen the check for null could fail if the another Thread will remove all the subscriber after the null checking and the actual invocation; another issue would be with thrown exceptions in the subscribers that would kill the chain…
In the next post we’ll see how to the events will help us and increase encapsulation and avoid these issue using only delegates

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s