Representing xsd:choice element in C#

The issue of correctly representing semantics of an xsd:choice element seemed like a good challenge, so I decided to tackle it.

Per XML Schema reference, xsd:choice is a group element, which allows one and only one of the elements contained in the group to be present within the containing element. If you try to translate this statement into the rough CLR terms, the parent instance of a type may contain only one instance out of a defined group of types. For example, suppose we have an instance of a Boat type, which can hold only a instance of a Cabbage type, an instance of a Goat type, or an instance of a Wolf type, but not any combination of those instances. What OOP concept does this sound like? That’s right, polymorphism. Let’s imagine an abstract class Load, from which Cabbage, Goat, and Wolf all inherit. Then, our declaration will look like so:

class Boat { public Load load; }

class Load { /* ... */ }

class Cabbage : Load { /* specific features of Cabbage */ }

class Goat : Load { /* specific features of Goat */ }

class Wolf : Load { /* specific features of Wolf */ }

Simple enough? Polyphormism-shmolymorphism, and we got ourselves a nice and semantically correct representation of a choice element. Unfortunately, as it so often happens in reality, all three of our instances competing for the coveted place on the Boat, must also inherit some of their traits from other base classes. For instance, Cabbage is also a Vegetable, Goat is a Herbivore, and Wolf is a Carnivore:

class Cabbage : Load, Vegetable { /* ... */ }

class Goat : Load, Herbivore { /* ... */ }

class Wolf : Load, Carnivore { /* ... */ }

As Steve Saxon pointed out in a comment to my previous post, you can’t do that in CLR — a type may inherit from only one base type. In these situations, you can simulate multiple inheritance using interfaces. Let’s redefine our Load class type as an interface:

interface ILoad {}

This interface is not doing much — it is there only to indicate that an instance of the type that implements this interface may be a load on the boat. Now, Cabbage, Goat, and Wolf can all both inherit their traits from base classes and also be marked as potential suitors for the boat ride:

class Cabbage : ILoad, Vegetable { /* ... */ }

class Goat : ILoad, Herbivore { /* ... */ }

class Wolf : ILoad, Carnivore { /* ... */ }

class Boat { public ILoad load; }

Now, let’s look at the definition of the Boat type. Although it can clearly carry one instance of ILoad, there is no indication of that exactly the load is — as the instances are cast into ILoad, all of their specifics are hidden by the marker interface. The type information is still available — all you need to do is to attempt to cast the instance of the load to one of the three types we’ve defined, and one of them is bound to be the answer, unless the boat is empty. Trying to be good programmers, we don’t want to leave this task entirely up to the developers who come behind us. So, with a few modifications, we can add management of boat loading and unloading. Here’s what we’ll do:

Inside Boat type, create a nested class called LoadManager:

public class Boat
{
/* ... */
public class LoadManager {}
}

This new type will contain one private field of type ILoad:

public class LoadManager
{
private ILoad _load;
}

Create accessor properties for each of our riverside travelers:

public class LoadManager
{
private ILoad _load;
public Cabbage Cabbage { get return _load as Cabbage; set _load = value; }
public Goat Goat { get return _load as Goat; set _load = value;}
public Wolf Wolf { get return _load as Wolf; set _load = value; }
}

As you can see, the logic of the LoadManager is slightly different from the plain ILoad implementation — now you have a 3 doors of different shapes leading to the same room instead of 1 door that changes shape depending on the entrant, yet they represent the same structure semantically.

To complete our journey, let’s modify the Boat type to have a property of LoadManager type rather than a field of ILoad type (we’ll also throw in lazy initialization just for kicks):

public class Boat
{
/* ... */
private LoadManager _loadManager;
public LoadManager Load { get if (_loadManager == null) _loadManager = new LoadManager(); return _loadManager; }
}

Whew! That was a long trip. However, at the end of the road, we’ve together some pretty code (full listing can be found here):

Boat boat = new Boat();
Console.WriteLine("Loading Cabbage...");
boat.Load.Cabbage = new Cabbage();
Console.WriteLine("Loading Goat...");
boat.Load.Goat = new Goat();
Console.WriteLine("Load is Cabbage: " + boat.Load.IsCabbage); // not likely
Console.WriteLine("Load is Goat: " + boat.Load.IsGoat);

What’s next? Well, how about figuring out how to implement a CLR representation of minOccurs and maxOccurs attributes of the same xsd:choice element?…

Leave a Reply

%d bloggers like this: