Dies ist eine alte Frage, aber ich habe mich kürzlich gefragt, ob so etwas möglich ist. Es scheint, dass es in C# keine Vererbung für Enums gibt und die einzige Möglichkeit, etwas wie dieses zu erstellen, wären benutzerdefinierte Klassen wie die Antwort von yoyo. Das Problem ist, dass es sich nicht wirklich um Enums handelt (kann z. B. nicht in switch-Anweisungen verwendet werden), und die Art des verschachtelten Codes erschwert das schnelle Lesen und Verstehen.
Ich fand, dass der einfachste Weg, um ähnliches Verhalten zu erhalten, war, eine einzelne, flache enum zu verwenden und die enums mit Attributen zu schmücken, die die Beziehungen (Vererbung) enthielten.Dies sorgt für viel einfacher zu lesen und zu verstehen, 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
}
Jetzt können die Aufzählungen wie normale Aufzählungen verwendet werden, und wir können ihre Beziehungen mit ein paar einfachen Erweiterungsmethoden untersuchen:
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<AnimalAttribute>().FirstOrDefault().GetType();
}
public static bool IsCat(this Enum value) { return value.HasAttribute<CatAttribute>(); }
public static bool IsDog(this Enum value) { return value.HasAttribute<DogAttribute>(); }
public static bool IsAnimal(this Enum value) { return value.HasAttribute<AnimalAttribute>(); }
public static bool IsReptile(this Enum value) { return value.HasAttribute<ReptileAttribute>(); }
public static bool IsSnake(this Enum value) { return value.HasAttribute<SnakeAttribute>(); }
public static bool IsLizard(this Enum value) { return value.HasAttribute<LizardAttribute>(); }
public static bool HasAttribute<T>(this Enum value)
{
var member = value.GetType().GetMember(value.ToString()).FirstOrDefault();
return member != null && Attribute.IsDefined(member, typeof(T));
}
public static string ToString<T>(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 ähnlich wie Jo-Jos:
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<AnimalAttribute>());
}
das einzige, was ist der Punkt-Zugriff Syntax von verschachtelten Klassen fehlen, aber wenn Sie nicht kritische Performance Code zu schreiben sind, können Sie som achive ething ähnlich mit Dynamik:
public static dynamic dogs
{
get {
var eo = new ExpandoObject() as IDictionary<string,object>;
foreach(var value in Enum.GetValues(typeof(Animal)).Cast<Animal>().Where(a => a.IsDog()))
eo[value.ToString()] = value;
return eo;
}
}
public static dynamic cats
{
get {
var eo = new ExpandoObject() as IDictionary<string,object>;
foreach(var value in Enum.GetValues(typeof(Animal)).Cast<Animal>().Where(a => a.IsCat()))
eo[value.ToString()] = value;
return eo;
}
}
Hinzufügen von Erweiterungsmethoden wie diese Sie Aufzählungen mit bestimmten Attributen zugreifen können, so dass Sie Variablen wie festlegen können:
Animal rhoda = Animals.dogs.greyhound;
Animal felix = Animals.cats.persian;
Wow, 5 Jahre später! Obwohl ich seitdem den Job zweimal gewechselt habe, erinnere ich mich, dass deine Lösung genau das ist, was ich damals wollte. Ihre Lösung zeigt eine Erklärung, Lösung, Implementierung und Ergebnisse: schön! Ich weiß es zu schätzen, dass Sie sich die Mühe gemacht haben, jemand anderen bei der gleichen Frage auf der ganzen Linie zu helfen, da diese Frage oft zu kommen scheint. – callisto
Danke @callisto, ich habe nicht unbedingt erwartet, dass das die "richtige" Antwort ist (nicht sicher, ob es wirklich eine gibt), aber wie gesagt, es hat mir Spaß gemacht und ich kann es vielleicht nutzen. (Nun, sollte es nicht ein Abzeichen geben, dass eine Antwort auf eine 5 Jahre alte Frage korrekt ist? ;-) – yoyo
In der Tat sollte es. Das "Vindicated" Abzeichen. – Robino