Enumeration Classes as Flags

In my last post I talked about serializing Enumeration Classes for use with WCF. In this post I’m gonna show you how to add a feature that real enums have but enumeration classes don’t. Yet!

Enums can be decorated with the FlagsAttribute. This allows you to combine single enum values using the ‘|’ operator. A sample from the System.Reflection namespace are BindingFlags.

BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

To find out wether a single value is part of such a combination you use the ‘&’ operator.

var flags = (BindingFlags.Public | BindingFlags.Instance) & BindingFlags.Public;

The result will be BindingFlags.Public.

To implement the same functionality for enumeration classes we need to define a class that implements both operators ‘|’ and ‘&’. This will be the base class for all flags classes

public abstract class Flags<T> : Enumeration where T : Flags<T>
{
  public Flags(int value, string displayName, string name)
    : base(value, displayName, name)
  {
  }
  public static T operator |(Flags<T> x, Flags<T> y)
  {
    return x.Or(y.ToEnumeration());
  }
  public static T operator &(Flags<T> x, Flags<T> y)
  {
    var f1 = x.ToArray();
    var f2 = y.ToArray();
    var f3 = f1.Intersect(f2).ToArray();
    if (f3.Length == 0)
    {
      return FromValue<T>(0);
    }
    if (f3.Length == 1)
    {
      return f3[0];
    }
    var or = f3[0].Or(f3[1]);
    for (int i = 2; i < f3.Length; i++)
    {
      or = or.Or(f3[i]);
    }
    return or;
  }
  protected internal virtual T[] ToArray()
  {
    return new[] { this.ToEnumeration() };
  }
  protected abstract T ToEnumeration();
  protected abstract T Or(T x);
}

To make our lives easier when implementing flags based on enumeration classes we will also use a generic helper class Or<T>.

public class Or<T> where T : Flags<T>
{
  private readonly List<T> flags;
  public Or(T x, T y)
  {
    this.flags = new List<T>();
    this.flags.AddRange(x.ToArray());
    this.flags.AddRange(y.ToArray());
  }
  public string Name
  {
    get
    {
      string[] names = this.flags.OrderBy(f => f.Value).Select(f => f.Name).ToArray();
      return String.Join(" ", names);
    }
  }
  public int Value
  {
    get { return this.flags.Sum(f => f.Value); }
  }
  public string DisplayName
  {
    get
    {
      string[] names = this.flags.OrderBy(f => f.Value).Select(f => f.DisplayName).ToArray();
      return String.Join(" ", names);
    }
  }
  public T[] ToArray()
  {
    return this.flags.ToArray();
  }
  public void Add(T x)
  {
    this.flags.AddRange(x.ToArray());
  }
}

Now we are armed to build a custom flags class with minimal effort.

public class Numbers : Flags<Numbers>
{
  public static Numbers None = new Numbers(0, "None");
  public static Numbers One = new Numbers(1, "One");
  public static Numbers Two = new Numbers(2, "Two");
  public static Numbers Four = new Numbers(4, "Four");

  private Numbers(int value, string name)
  : base(value, name, name)
  {
  }
  protected override Numbers ToEnumeration()
  {
    return this;
  }
  protected override Numbers Or(Numbers x)
  {
    return new OredNumbers(this, x);
  }
  private class OredNumbers : Numbers
  {
    private readonly Or<Numbers> flags;
    public OredNumbers(Numbers x, Numbers y)
      : base(-1, String.Empty)
    {
      this.flags = new Or<Numbers>(x, y);
    }
    public override string Name
    {
      get { return this.flags.Name; }
    }
    public override string DisplayName
    {
      get { return this.flags.DisplayName; }
    }
    public override int Value
    {
      get { return this.flags.Value; }
    }
    protected internal override Numbers[] ToArray()
    {
      return this.flags.ToArray();
    }
    protected override Numbers Or(Numbers x)
    {
      this.flags.Add(x);
      return this;
    }
  }
}

Admittedly this is much more code than you would have to write for simple flags based on an enum. But the additional power of enumeration classes can also be found in the flags classes. Think of a user selecting from a set of predefined filter criteria. As long as Microsoft does not make expressions serializable you have no way of dynamically building the desired filter on the client side and send it to the server for evaluation other than directly accessing your database (be it SQL or NoSQL) and let some LINQ provider do the translation from expression to native query for you. With flags classes you can combine an abstraction of your filters on the client side, send the flags and let WCF do the reconstruction of the filters on the server side.

The complete source code is available here (project TecX.EnumClasses and the test suite that puts them to use can be found in TecX.EnumClasses.Test). There is a separate solution file TecX.EnumClasses as well.

Enumeration Classes and WCF

During the last week I was working on a real fun project. It started after I stumbled across an old article by Jimmy Bogard, author of the famous AutoMapper library. In his post he talks about Enumeration Classes. What they are, how they work and what their advantages over simple enums are.

He started by stating that a certain question evolved from a discussion on ALT.NET: “What do you do about enumerations crossing service boundaries?”. His post is inspiring but he did not really give an answer to that exact question.

Although WCF is by no means the only way to implement “services” this unanswered question got me thinking: “What if I want to use functionality-enhanced enumeration classes in a WCF service and simple enums on the client side?”

I know that WCF was designed to “talk dirty” when it comes to conversion between client- and server-side objects. It doesn’t matter if you have classes on one and structs on the other side. They don’t have to have the same (number of) fields. Using the DataMemberAttribute you can name the fields differently or even forward information a certain client does not use in its contracts further down the stream when that client calls another service by implementing IExtensibleDataObject in your objects.

But can it talk enums on the client and enumeration classes on the server? As it turns out: Yes it can!

The SortOrder Enumeration Class

For the following sample I will use a modified version of the SortOrder enumeration class I grabbed from the Tarantino project Jimmy mentions in his article. One of the changes I made to the enumeration base class is to introduce a Name property in addition to the DisplayName. That allows you to handle enumeration classes in a very similar way to real enums. I also added non-generic overloads for the FromValue and FromName methods. This is the modified SortOrder enumeration class.

[Serializable]
public class SortOrder : Enumeration
{
  public static readonly SortOrder Ascending = new AscendingSortOrder();
  public static readonly SortOrder Descending = new DescendingSortOrder();
  private readonly IComparer comparer;
  public SortOrder()
  {
  }
  public SortOrder(int value, string displayName, string name, IComparer comparer)
    : base(value, displayName, name)
  {
    this.comparer = comparer;
  }
  public IComparer Comparer
  {
    get { return comparer; }
  }
  private class AscendingSortOrder : SortOrder
  {
    public AscendingSortOrder()
      : base(0, "Sort ascending", "Ascending", StringComparer.OrdinalIgnoreCase)
    {
    }
  }
  private class DescendingSortOrder : SortOrder
  {
    public DescendingSortOrder()
      : base(1, "Sort descending", "Descending", new DescendingStringComparer())
    {
    }
    private class DescendingStringComparer : IComparer
    {
      public int Compare(string x, string y)
      {
        return -StringComparer.OrdinalIgnoreCase.Compare(x, y);
      }
    }
  }
}

Control (De-)Serialization with IDataContractSurrogate

The task is not quite as easy as I thought at first. The WCF infrastructure gives us the IDataContractSurrogate interface. By implementing this interface you can control how WCF serializes and deserializes specific objects.

Serialization is easy. When WCF calls the GetDataContractType method you return typeof(string) and in your implementation of the GetObjectToSerialize method you return the value of the Name property of your enumeration class and the resulting XML looks exactly as if you were serializing a simple enum. But the real deal is the deserialization. WCF matches the incoming serialized enum to the enumeration class. So far so good. But WCF is not able to convert the serialized input value to the matching enumeration class. If you try to use that enumeration type directly without modifying it on the call to GetDataContractTye WCF will fail with an exception. It can’t do the deserialization with the information it has. But it won’t call GetDeserializedObject for help either. If you return typeof(string) WCF will fail as well telling you it can’t cast a string to your enumeration class type. Even if you implement an implicit or explicit cast operator from string to your enumeration you will get that exception. And it also won’t call GetDeserializedObject. A somewhat strange behavior but there you are.

But I was not willing to give up. If WCF can’t handle primitive values like strings and can’t handle your enumeration class directly but it can handle enums, why not try to treat the incoming value as a custom enum and convert that enum to your enumeration class? I know that sounds stupid. You don’t want to write and maintain code for an enumeration class and an enum on the server side. But you don’t have to. Some prior experiments with emitting IL code taught me that it is very easy to generate such an enum on-the-fly.

Reflection.Emit to the Rescue

So what I did is I created an IL generator that checks wether it already emitted an enum type for a specific enumeration class. If not it dynamically creates an enum type that has the same name as the enumeration class plus a short suffix. It also creates an enum member for every static field in your enumeration class (like SortOrder.Ascending) with the name of the field and the value of the enumeration class, decorates type and members with the DataContract- and EnumMemberAttributes and remembers that type for future use.

For SortOrder the generator creates the following enum:

[DataContract(Name="SortOrder")]
public enum SortOrder_Enum
{
  [EnumMember]
  Ascending = 0,
  [EnumMember]
  Descending = 1
}

See no Evil…

And all of a sudden everything works like a charm. The modified surrogate returns the enum type when asked for the DataContractType and you can handle conversion from enum to enumeration class by using the non-generic methods Enumeration.FromValue(Type, int) or Enumeration.FromName(Type, string) in the call to GetDeserializedObject.

public class EnumerationClassesSurrogate : IDataContractSurrogate
{
  private readonly EnumGenerator generator;
  public EnumerationClassesSurrogate()
  {
    this.generator = new EnumGenerator();
  }
  public Type GetDataContractType(Type type)
  {
    if (typeof(Enumeration).IsAssignableFrom(type))
    {
      Type enumType;
      if (this.generator.TryGetEnumByType(type, out enumType))
      {
        return enumType;
      }
    }
    return type;
  }
  public object GetObjectToSerialize(object obj, Type targetType)
  {
    Enumeration enumeration = obj as Enumeration;
    if (enumeration != null)
    {
      Type enumType;
      if (this.generator.TryGetEnumByType(obj.GetType(), out enumType) &&
          Enum.IsDefined(enumType, enumeration.Name))
      {
        return Enum.Parse(enumType, enumeration.Name);
      }
    }
    return obj;
  }
  public object GetDeserializedObject(object obj, Type targetType)
  {
    Type objType = obj.GetType();
    if (this.generator.IsGeneratedEnum(objType) &&
        typeof(Enumeration).IsAssignableFrom(targetType))
    {
      string name = Enum.GetName(objType, obj);
      return Enumeration.FromName(targetType, name);
    }
    return obj;
  }

  // other methods are not implemented for this sample
}

Serialization works in the same way. You map the enumeration class type to the generated enum type and convert the enumeration value to the matching enum value. All of this is completely transparent for client and server code.

[TestMethod]
public void Should_TransparentlyConvert_BetweenSimpleEnumOnClient_AndComplexEnumClassOnServer()
{
  IEnumerable sms = new[]
    {
      new SerializeMe2 { Text = "1" },
      new SerializeMe2 { Text = "3" },
      new SerializeMe2 { Text = "2" }
    };
  using (ServiceHost host = new ServiceHost(typeof(SortingService), new Uri("http://localhost:12345/svc")))
  {
    host.Open();
    var factory = new ChannelFactory(new BasicHttpBinding());
    var proxy = factory.CreateChannel(new EndpointAddress("http://localhost:12345/svc"));
    var result = proxy.Sort(sms, SortOrderEnum.Ascending).ToList();
    Assert.AreEqual("1", result[0].Text);
    Assert.AreEqual("2", result[1].Text);
    Assert.AreEqual("3", result[2].Text);
  }
}

[ServiceContract]
public interface ISortingService
{
  [OperationContract]
  IEnumerable Sort(IEnumerable itemsToSort, SortOrder sortOrder);
}
[ServiceContract(Name = "ISortingService")]
public interface ISortingServiceClient
{
  [OperationContract]
  IEnumerable Sort(IEnumerable itemsToSort, SortOrderEnum sortOrder);
}
[PutDataContractSurrogateBehavior]
public class SortingService : ISortingService
{
  public IEnumerable Sort(IEnumerable itemsToSort, SortOrder sortOrder)
  {
    return itemsToSort.OrderBy(s => s.Text, sortOrder.Comparer);
  }
}
[DataContract(Name = "SortOrder")]
public enum SortOrderEnum
{
  [EnumMember]
  Ascending,
  [EnumMember]
  Descending
}

What you get

Maybe you don’t consider sorting to be a worldshaking example to demonstrate the advantages of enumeration classes. But I believe that, within the boundaries of a HelloWorld! sample, it shows you quite nicely what this pattern has to offer. Enumeration classes are yet another tool in your toolbox. Use them when they seem to fit your requirements.

The posiblity to use simple enums in your clients while you reserve the much more powerful enumeration classes for the server side helps you to decouple client and server and reduce the complexity of your code. See how simple it is to sort values based on the additional information stored in your enumeration classes. The client does not have to know about that. And the server does not need to know that the client doesn’t know…

The complete source code is available here (project TecX.EnumClasses and the test suite that puts them to use can be found in TecX.EnumClasses.Test). There is a separate solution file TecX.EnumClasses as well.