你可以在运行时添加到枚举类型

如果我有枚举类型:

Public enum Sport { Tennis = 0; Football = 1; Squash = 2; Volleyball = 3; } 

我可以在运行时以某种方式添加:

 PingPong = 4 

枚举有一个后备存储,如果你没有指定它,则默认为int。 可以直接指定定义值之外的值:

 Sport pingPong = (Sport)4; 

然后你可以检查它:

 if (value == (Sport)4) {} 

这就是为什么你有静态函数Enum.IsDefined()来检查实际值是否在预期值内。 请注意,该函数不适用于复合标志值。

 bool isValueDefined = Enum.IsDefined(typeof(Sport), value); 

编辑:在Hans Passant评论之后:你不必使用文字值4.你可以使用任何返回int的东西。 例如:

 Dictionary AdditionalSports = new Dictionary(); AdditionalSports.Add(4, "PingPong"); // Usages: if if (AdditionalSports.ContainsKey(value)) { // Maybe do something with AdditionalSports[value], ie "PingPong" } // In a switch: switch (value) { case default: // Since it won't be found in the enum-defined values if (AdditionalSports.ContainsKey(value)) { // Maybe do something with AdditionalSports[value], ie "PingPong" } } 

这里有更多以面向对象的方式来实现您想要实现的目标。 这个解决方案的灵感来自早期的Java枚举方法:

 struct Sport { readonly int value; public Sport(int value) { this.value = value; } public static implicit operator int(Sport sport) { return sport.value; } public static implicit operator Sport(int sport) { return new Sport(sport); } public const int Tennis = 0; public const int Football = 1; public const int Squash = 2; public const int Volleyball = 3; } //Usage: Sport sport = Sport.Volleyball; switch(sport) { case Sport.Squash: Console.WriteLine("I bounce really high"); break; } Sport rugby = 5; if (sport == rugby) Console.WriteLine("I am really big and eat a lot"); 

了解此解决方案的不同特点。

  1. 它是一个包含整数值的不可变结构。 该值由readonly关键字强制执行。

  2. 创建其中一个结构的唯一方法是调用将值作为参数的构造函数。

  3. implicit operator int是存在的,因此结构可以在switch bock中使用 – 即使结构可转换为int

  4. implicit operator Sport是存在的,因此您可以为结构分配整数值,即Sport rugby = 5

  5. const值是编译时已知的运动。 它们也可以用作case标签。

我会做什么

 public static class Sports { public static readonly Sport Football = new Sport("Football"); public static readonly Sport Tennis = new Sport("Tennis"); } public class Sport { public Sport(string name) { Name = name; } public string Name { get; private set; } // override object.Equals public override bool Equals(object obj) { var other = obj as Sport; if(other == null) { return false; } return other == this; } // override object.GetHashCode public override int GetHashCode() { return Name.GetHashCode(); } public static bool operator == (Sport sport1, Sport sport2) { if(Object.ReferenceEquals(sport1, null) && Object.ReferenceEquals(sport2 , null)) return true; if(Object.ReferenceEquals(sport1, null) || Object.ReferenceEquals(sport2, null)) return false; return sport1.Name == sport2.Name; } public static bool operator !=(Sport sport1, Sport sport2) { return !(sport1 == sport2); } } 

这将创建一个具有名称的价值类Sport 。 根据您的应用程序,您可以扩展此类以提供其他属性和方法。 将其作为类可以为您提供更多的灵活性,因为您可以将其子类化。

Sports提供在编译时已知的静态运动集合。 这类似于某些.NET框架处理命名颜色(即WPF)的方式。 这是用法:

 List sports = new List(); sports.Add(Sports.Football); sports.Add(Sports.Tennis); //What if the name contains spaces? sports.Add(new Sport("Water Polo")); var otherSport = new Sport("Other sport"); if(sports.Contains(otherSport)) { //Do something } foreach(var sport in sports) { if(sport == otherSport) { //Do Something } else if(sport == Sports.Football) { //do something else } } 

一旦你这样做,你会发现实际上很少需要枚举,因为运动类型的任何条件操作都可以在Sport类中处理。

编辑实现我的相等运算符将抛出一个StackOverflowException我总是忘记编写Object.ReferenceEquals(obj,null)而不是obj==null ,这将无限递归。

不,您无法在运行时修改类型。 您可以发出新类型,但无法修改现有类型。

是的,您可以使用EnumBuilder类在运行时创建和/或更改Enum,请参阅MSDN中的示例

 ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll"); EnumBuilder eb = mb.DefineEnum("Elevation", TypeAttributes.Public, typeof(int)); eb.DefineLiteral("Low", 0); eb.DefineLiteral("High", 1); Type finished = eb.CreateType(); 

在我看来,拥有枚举值比字典或基于列表的解决方案更好,因为使用更少的内存和没有线程副作用。

以下是一些有关如何在重新启动应用程序时加载生成的枚举的示例 。 我建议你选择一个适合你的方法,你可以使用System.AddIn命名空间提供的方法,或者使用你的IoC。

当我需要为机器学习生成数据时,我使用这个,因为它具有Enum值,并且优于查找表(在数据库的内存中),因为我没有这些大数据集可用的IO。

快乐的编码

沃尔特

如果可以在程序启动时定义枚举,则将枚举放在单独的程序集中,并使用将重新编译枚举的引导程序,覆盖旧版本,然后启动实际应用程序。 这不是最干净的方法,但它有效。

我会创建一个完整的枚举,具有您将需要的所有值

 Public enum Sport { Tennis = 0; Football = 1; Squash = 2; Volleyball = 3; PingPong = 4; Rugby = 5; // for example } 

然后保留无效运动条目的列表,因此该列表最初将包含PingPongRugby 。 每次访问枚举时,也请检查您的无效运动列表。

然后,您可以在任何阶段简单地调整您的无效运动列表以适应