public static void Main()
OtherClass oc = new OtherClass
Description = "Other Description"
string json = JsonConvert.SerializeObject(oc);
OtherClass oc2 = JsonConvert.DeserializeObject<OtherClass>(json);
Console.WriteLine("Color: " + oc2.Color.Value + " (" + oc2.Color.DisplayName + ")");
Console.WriteLine("Description: " + oc2.Description);
public Color Color { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(EnumerationConverter<Color>))]
public class Color : Headspring.Enumeration<Color, int>
public static readonly Color Red = new Color(1, "Red");
public static readonly Color Blue = new Color(2, "Blue");
public static readonly Color Green = new Color(3, "Green");
private Color(int value, string displayName) : base(value, displayName) { }
class EnumerationConverter<T> : JsonConverter where T : Headspring.Enumeration<T, int>
public override bool CanConvert(Type objectType)
return objectType == typeof(T);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
int val = Convert.ToInt32(reader.Value);
return Headspring.Enumeration<T, int>.FromValue(val);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var enumVal = (Headspring.Enumeration<T, int>)value;
writer.WriteValue(enumVal.Value);
public abstract class Enumeration<TEnumeration> : Enumeration<TEnumeration, int>
where TEnumeration : Enumeration<TEnumeration>
protected Enumeration(int value, string displayName)
: base(value, displayName)
public static TEnumeration FromInt32(int value)
public static bool TryFromInt32(int listItemValue, out TEnumeration result)
return TryParse(listItemValue, out result);
public abstract class Enumeration<TEnumeration, TValue> : IComparable<TEnumeration>, IEquatable<TEnumeration>
where TEnumeration : Enumeration<TEnumeration, TValue>
where TValue : IComparable
private static readonly Lazy<TEnumeration[]> Enumerations = new Lazy<TEnumeration[]>(GetEnumerations);
[JsonProperty(Order = 1)]
readonly string _displayName;
[JsonProperty(Order = 0)]
protected Enumeration(TValue value, string displayName)
throw new ArgumentNullException("value");
_displayName = displayName;
public string DisplayName
get { return _displayName; }
public int CompareTo(TEnumeration other)
return Value.CompareTo(other == default(TEnumeration) ? default(TValue) : other.Value);
public override sealed string ToString()
public static TEnumeration[] GetAll()
return Enumerations.Value;
private static TEnumeration[] GetEnumerations()
Type enumerationType = typeof(TEnumeration);
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
.Where(info => enumerationType.IsAssignableFrom(info.FieldType))
.Select(info => info.GetValue(null))
public override bool Equals(object obj)
return Equals(obj as TEnumeration);
public bool Equals(TEnumeration other)
return other != null && ValueEquals(other.Value);
public override int GetHashCode()
return Value.GetHashCode();
public static bool operator ==(Enumeration<TEnumeration, TValue> left, Enumeration<TEnumeration, TValue> right)
return Equals(left, right);
public static bool operator !=(Enumeration<TEnumeration, TValue> left, Enumeration<TEnumeration, TValue> right)
return !Equals(left, right);
public static TEnumeration FromValue(TValue value)
return Parse(value, "value", item => item.Value.Equals(value));
public static TEnumeration Parse(string displayName)
return Parse(displayName, "display name", item => item.DisplayName == displayName);
static bool TryParse(Func<TEnumeration, bool> predicate, out TEnumeration result)
result = GetAll().FirstOrDefault(predicate);
private static TEnumeration Parse(object value, string description, Func<TEnumeration, bool> predicate)
if (!TryParse(predicate, out result))
string message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(TEnumeration));
throw new ArgumentException(message, "value");
public static bool TryParse(TValue value, out TEnumeration result)
return TryParse(e => e.ValueEquals(value), out result);
public static bool TryParse(string displayName, out TEnumeration result)
return TryParse(e => e.DisplayName == displayName, out result);
protected virtual bool ValueEquals(TValue value)
return Value.Equals(value);