Skip to content

Instantly share code, notes, and snippets.

@slovely
Created July 11, 2011 17:47
Show Gist options
  • Save slovely/1076365 to your computer and use it in GitHub Desktop.
Save slovely/1076365 to your computer and use it in GitHub Desktop.
Type-safe Enumerations in c#
public class MyType : Enumeration
{
//don't allow type to be constructed
private MyType(int value, string displayName) : base(value, displayName) { }
public static readonly MyType Type1 = new MyType(1, "Type One");
public static readonly MyType Type2 = new MyType(2, "Type Two");
public static readonly MyType DerivedType3 = new DerivedMyType(3, "Type Three");
public virtual int GetSomethingAboutThisType()
{
//Can implement some logic here (which could switch on this.Value if you really wanted)
if (Value == 1)
return 10;
return 42;
}
//Or we can move logic to derived types to make it cleaner (cos it's a private nested class
//no one else can see it as well which is good, and we only expose it as the base 'MyType' type)
private class DerivedMyType : MyType
{
public DerivedMyType(int value, string displayName) : base(value, displayName) { }
public override int GetSomethingAboutThisType()
{
return 150;
}
}
}
//based on Jimmy Bogard's post here: http://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/
//But modified to lose the "new ()" where clause as it's not needed.
public abstract class Enumeration : IComparable
{
private readonly int _value;
private readonly string _displayName;
protected Enumeration()
{
}
protected Enumeration(int value, string displayName)
{
_value = value;
_displayName = displayName;
}
public int Value
{
get { return _value; }
}
public string DisplayName
{
get { return _displayName; }
}
public override string ToString()
{
return DisplayName;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration
{
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
return fields.Select(info => info.GetValue(null)).OfType<T>();
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = _value.Equals(otherValue.Value);
return typeMatches && valueMatches;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static T FromValue<T>(int value) where T : Enumeration
{
var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
return matchingItem;
}
public static T FromDisplayName<T>(string displayName) where T : Enumeration
{
var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
return matchingItem;
}
private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration
{
var matchingItem = GetAll<T>().FirstOrDefault(predicate);
if (matchingItem == null)
{
var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
throw new ApplicationException(message);
}
return matchingItem;
}
public int CompareTo(object other)
{
return Value.CompareTo(((Enumeration)other).Value);
}
}
@slovely
Copy link
Author

slovely commented Oct 4, 2021

Any way to use such enum as default value in method (compiler requires static constant) ?

Apologies, 3.5 years late.... no, you are correct that is a downside of this approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment