Switchers revisited in C#

For reasons that I will never understand, Microsoft’s C# does not support anonymous classes. So when applying the Switcher pattern in C#, we need to take a different approach to implementation.

A word of warning: this posting discusses the Switcher pattern that I introduced in an earlier posting. If you have not read this earlier posting, I would suggest doing so before proceeding, as it provides some fairly fundamental exposition.

Again, let’s start with some simple classes that require class-dependent processing. We’ll use fruit instead of animals this time, so nobody accidentally tries to mix Java code from previous posting with C# code from this one.


public abstract class Fruit { }
public class Banana : Fruit { }
public class Plum : Fruit { }

Here is the version of the client code that’s practically begging to malfunction once a new subclass of Fruit is introduced:


Fruit F = getRandomFruit();
if (F is Banana) {
	Banana B = (Banana)F;
	B.peel();
	B.eat();
} else if (F is Plum) {
	Plum P = (Plum)F;
	P.eat();
	spitOut(P.stone);
}

In C#, I implement the Switcher pattern using delegate methods (which are basically type-safe function pointers) that are passed as arguments to a Switcher method in an abstract Switcher class:


public abstract class FruitSwitcher {
	public delegate void BananaMethod (Banana B);
	public delegate void PlumMethod (Plum P);

	public static void switchAll(
		BananaMethod onBanana,
		PlumMethod onPlum,
		Fruit F)
	{
		if (F is Banana) {
			onBanana((Banana)F);
		} else if (F is Plum) {
			onPlum((Plum)F);
		}
	}
}

Client code can then use the Switcher class thusly:


Fruit F = getRandomFruit();
FruitSwitcher.switchAll(
	delegate(Banana B) {
		B.peel();
		B.eat();
	},
	delegate(Plum P) {
		P.eat();
		spitOut(P.stone);
	},
	F
);

This approach offers a number of features not included in the previous, Java-based Switcher class.

Firstly, the Switcher class offers class-switching logic as static methods rather than as constructors. This has the advantage that a single Switcher class can implement various collections:


public abstract class FruitSwitcher {
	/* Delegate method definitions omitted */

	public static void switchAll(
		BananaMethod onBanana,
		PlumMethod onPlum,
		LemonMethod onLemon,
		OrangeMethod onOrange,
		Fruit F)
	{ /* Implementation details omitted */ }

	public static void switchCitrus(
		LemonMethod onLemon,
		OrangeMethod onOrange,
		Fruit F)
	{ /* Implementation details omitted */ }
}

Secondly, the delegate methods each include a parameter containing the original object, just re-cast to the respective class. This is for two reasons:

Other features are of course also possible, including code for dealing with null values (which could either throw an exception, or call a delegate onNull method). There is also no rule that states the Switcher method has to have the void return type; for example, we could implement FruitSwitcher.switchAll(...) so that the client code’s delegate method returns the color of the fruit.

Comments

Leave a Reply