2013-10-21

Safe Enum Pattern

Here’s my implementation of the Safe Enum Pattern.

Why? Because Enums are kind of cumbersome to handle, and you need to use methods like Enum.Parse and Enum.ToObject etc, and you cannot compare them to string without casting them to string.

I just wanted to collect all my constant strings in one place, and also allow them to be constrained to a set of values, so that I can send them as parameters to a function knowing that only my predefined legal values will be allowed.

So to make it easy to compare them I have implemented the IEquatable<T> interface, and also operator overloading on the == and != operators, so that I can do this:

PropertyName myPropertyName = getPropertyName();
if(myPropertyName == “test”) { /*… do stuff */ }

I can also have a function like this:

public object GetPropertyValue(PropertyName propertyName)
{
    ….
}

And I am guaranteed that only my set of valid strings will be allowed as a parameter, like enums really.

Well, here’s the code:

public class SafeEnumBase : IEquatable<string>, IEquatable<SafeEnumBase>
{
    
public SafeEnumBase(string name) { Name = name; }
     public string Name { get; protected set; }
     public override string ToString() { return Name; }
     #region IEquatable<T> implementetion
     public bool Equals(string other)
     {
         return (other == Name);
     }
     public bool Equals(SafeEnumBase other)
     {
         return (other.Name == Name);
     }
     #endregion
     #region OPERATOR OVERLOADING allows comparing objects to strings and objects to objects without need to specify which property to compare
     public static bool operator ==(SafeEnumBase p1, PropertyName p2)
     {
         return p1.Equals(p2);
     }
     public static bool operator !=(SafeEnumBase p1, PropertyName p2)
     {
         return !p1.Equals(p2);
     }
     public static bool operator ==(SafeEnumBase p1, string p2)
     {
         return p1.Equals(p2);
     }
     public static bool operator !=(SafeEnumBase p1, string p2)
     {
         return !p1.Equals(p2);
     }
     #endregion


}



public sealed class PropertyName : SafeEnumBase

{
     private PropertyName(string name) : base(name) { }

     public static readonly PropertyName ID = new PropertyName("ID");
     public static readonly PropertyName NAME = new PropertyName("NAME");
     public static readonly PropertyName NUMBER = new PropertyName("NUMBER");
     public static readonly PropertyName TYPE = new PropertyName("TYPE");

}


public sealed class ClassName : SafeEnumBase
{
     private ClassName(string name) : base(name) { }


     public static readonly PropertyName CUSTOMER = new PropertyName("CUSTOMER");
     public static readonly PropertyName EMPLOYEE = new PropertyName("EMPLOYEE");
     public static readonly PropertyName ADMIN = new PropertyName("ADMIN");
     public static readonly PropertyName TYPE = new PropertyName("TYPE");
}