I want to declare a nested enum like:
\\\\pseudocode
public enum Animal
{
dog = 0,
cat = 1
}
private enum dog
{
bulldog = 0,
greyhound = 1,
hus
This is an old question, but I recently wondered if something like this was possible. It seems that in C# there is nothing like inheritance for enums and the only way to create something like this would be custom classes like yoyo's answer. The problem is that they aren't really enums (can't be used in switch statements for instance), and the nature of the nested code makes it difficult to read and understand quickly.
I found that the easiest way to get similar behavior was to use a single, flat enum and decorate the enums with Attributes that contained the relationships (inheritance). This makes for much easier to read and understand code:
class AnimalAttribute : Attribute {}
class DogAttribute : AnimalAttribute {}
class CatAttribute : AnimalAttribute {}
class ReptileAttribute : AnimalAttribute {}
class SnakeAttribute : ReptileAttribute {}
class LizardAttribute : ReptileAttribute {}
enum Animal
{
[Dog] bulldog,
[Dog] greyhound,
[Dog] husky,
[Cat] persian,
[Cat] siamese,
[Cat] burmese,
[Snake] adder,
[Snake] boa,
[Snake] cobra,
[Lizard] gecko,
[Lizard] komodo,
[Lizard] iguana,
[Lizard] chameleon
}
Now the enums can be used just like normal enums, and we can examine their relationships with a few simple extension methods:
static class Animals
{
public static Type AnimalType(this Enum value )
{
var member = value.GetType().GetMember(value.ToString()).FirstOrDefault();
// this assumes a single animal attribute
return member == null ? null :
member.GetCustomAttributes()
.Where(at => at is AnimalAttribute)
.Cast().FirstOrDefault().GetType();
}
public static bool IsCat(this Enum value) { return value.HasAttribute(); }
public static bool IsDog(this Enum value) { return value.HasAttribute(); }
public static bool IsAnimal(this Enum value) { return value.HasAttribute(); }
public static bool IsReptile(this Enum value) { return value.HasAttribute(); }
public static bool IsSnake(this Enum value) { return value.HasAttribute(); }
public static bool IsLizard(this Enum value) { return value.HasAttribute(); }
public static bool HasAttribute(this Enum value)
{
var member = value.GetType().GetMember(value.ToString()).FirstOrDefault();
return member != null && Attribute.IsDefined(member, typeof(T));
}
public static string ToString(this Animal value) where T : AnimalAttribute
{
var type = value.AnimalType();
var s = "";
while( type != null && !(type == typeof(Object)) )
{
s = type.Name.Replace("Attribute","") + "."+s;
type = type.BaseType;
}
return s.Trim('.');
}
}
Test similar to yoyos:
void Main()
{
Animal rover = Animal.bulldog;
Animal rhoda = Animal.greyhound;
Animal rafter = Animal.greyhound;
Animal felix = Animal.persian;
Animal zorrow = Animal.burmese;
Animal rango = Animal.chameleon;
if( rover.IsDog() )
Console.WriteLine("rover is a dog");
else
Console.WriteLine("rover is not a dog?!");
if( rover == rhoda )
Console.WriteLine("rover and rhonda are the same type");
if( rover.AnimalType() == rhoda.AnimalType() )
Console.WriteLine("rover and rhonda are related");
if( rhoda == rafter )
Console.WriteLine("rhonda and rafter are the same type");
if( rango.IsReptile() )
Console.WriteLine("rango is a reptile");
Console.WriteLine(rover.ToString());
}
The only thing missing is the dot-access syntax of nested classes, but if you are not writing performance critical code you can achive something similar with dynamics:
public static dynamic dogs
{
get {
var eo = new ExpandoObject() as IDictionary;
foreach( var value in Enum.GetValues(typeof(Animal)).Cast().Where(a => a.IsDog()))
eo[value.ToString()] = value;
return eo;
}
}
public static dynamic cats
{
get {
var eo = new ExpandoObject() as IDictionary;
foreach( var value in Enum.GetValues(typeof(Animal)).Cast().Where(a => a.IsCat()))
eo[value.ToString()] = value;
return eo;
}
}
Adding extension methods like these allows you to access enums with specific attributes, so you can set variables as:
Animal rhoda = Animals.dogs.greyhound;
Animal felix = Animals.cats.persian;