工作中许多代码中用到枚举(enum),更用到了需要继承的枚举,由于C#的枚举不允许被继承(但允许继承自int/float等类型,这个不是我要的,在此不讨论)。
我实现了一个可以继承的模拟枚举,在此与各位分享。
于是我努力制造出可以继承的枚举,确切地说是可以继承的“仿枚举”。
首先要仿System.Enum造一个仿它的地位的类,以“操控一切”。它也是一切可继承枚举的鼻祖。
此类要承担诸多功能:
1.与int/string之间的相互转换
2.支持实例(静态属性)指定或不指定数值
3.一些辅助的功能,如比较大小等
4.一些方便使用的功能,如ForEach方法
5.像string类(class)一样,表现出值传递的效果
using System; using System.Collections; using System.Collections.Generic; namespace HeritableEnum { public class HEnum : IComparable<HEnum>, IEquatable<HEnum> { static int counter = -1; //默认数值计数器 private static Hashtable hashTable = new Hashtable(); //不重复数值集合 protected static List<HEnum> members = new List<HEnum>(); //所有实例集合 private string Name { get; set; } private int Value { get; set; } /// <summary> /// 不指定数值构造实例 /// </summary> protected HEnum(string name) { this.Name = name; this.Value = ++counter; members.Add(this); if (!hashTable.ContainsKey(this.Value)) { hashTable.Add(this.Value, this); } } /// <summary> /// 指定数值构造实例 /// </summary> protected HEnum(string name, int value) : this(name) { this.Value = value; counter = value; } /// <summary> /// 向string转换 /// </summary> /// <returns></returns> public override string ToString() { return this.Name.ToString(); } /// <summary> /// 显式强制从int转换 /// </summary> /// <param name="i"></param> /// <returns></returns> public static explicit operator HEnum(int i) { if (hashTable.ContainsKey(i)) { return (HEnum)members[i]; } return new HEnum(i.ToString(), i); } /// <summary> /// 显式强制向int转换 /// </summary> /// <param name="e"></param> /// <returns></returns> public static explicit operator int(HEnum e) { return e.Value; } public static void ForEach(Action<HEnum> action) { foreach (HEnum item in members) { action(item); } } public int CompareTo(HEnum other) { return this.Value.CompareTo(other.Value); } public bool Equals(HEnum other) { return this.Value.Equals(other.Value); } public override bool Equals(object obj) { if (!(obj is HEnum)) return false; return this.Value == ((HEnum)obj).Value; } public override int GetHashCode() { HEnum std = (HEnum)hashTable[this.Value]; if (std.Name == this.Name) return base.GetHashCode(); return std.GetHashCode(); } public static bool operator !=(HEnum e1, HEnum e2) { return e1.Value != e2.Value; } public static bool operator <(HEnum e1, HEnum e2) { return e1.Value < e2.Value; } public static bool operator <=(HEnum e1, HEnum e2) { return e1.Value <= e2.Value; } public static bool operator ==(HEnum e1, HEnum e2) { return e1.Value == e2.Value; } public static bool operator >(HEnum e1, HEnum e2) { return e1.Value > e2.Value; } public static bool operator >=(HEnum e1, HEnum e2) { return e1.Value >= e2.Value; } } }
经过时间跨度很长中的N次尝试后,写成了上面这个样子,实现了最基本的功能。ForEach后面都是直接或间接为了“比较大小”要写的方法。
值得强调的是此类的所有构造方法必须是protected,以防止在类之外构造实例。它的子类也必须这样,以下是用于演示的子类:
class EnumUse1 : HEnum { protected EnumUse1(string name) : base(name) { } protected EnumUse1(string name, int value) : base(name, value) { } public static EnumUse1 A = new EnumUse1("A"); public static EnumUse1 B = new EnumUse1("B", 2); public static EnumUse1 C = new EnumUse1("C", 2); public static EnumUse1 D = new EnumUse1("D"); }
EnumUse1从HEnum继承,模拟以下的代码
enum EnumUse1 { A, B = 2, C = 2, D }
再有一个子类从EnumUse1继承:
class EnumUse2 : EnumUse1 { protected EnumUse2(string name) : base(name) { } protected EnumUse2(string name, int value) : base(name, value) { } public static EnumUse2 E = new EnumUse2("E"); }
用起来跟系统原生的enum很像
class Program { static void Main(string[] args) { bool b = EnumUse1.D >= EnumUse1.A; Console.WriteLine(b.ToString()); Show(EnumUse2.E); HEnum.ForEach((x) => Console.WriteLine("{0} = {1},", x, (int)x)); } static void Show(HEnum e) { Console.WriteLine(@"{0} = {1},""{2}""", e, (int)e, e.ToString()); } }
看,现在做到了可以比较大小,可以转化成string,(从string转回暂未做,但也不难),可以与int互转,值传递的效果(演示中无体现)。还比原生的enum多了ForEach功能,这点很方便。运行结果:
True
E = 4,"E"
A = 0,
B = 2,
C = 2,
D = 3,
E = 4,
话说回来,此类还有诸多不足,充其量只能算是一个实验品,想要真正走向实用,还有些工作要做。在此发布,纪念此次实验及成果。