利用C#实现可以继承的"枚举"
工作中许多代码中用到枚举(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, iequatable { static int counter = -1; //默认数值计数器 private static hashtable hashtable = new hashtable(); //不重复数值集合 protected static list members = new list(); //所有实例集合 private string name { get; set; } private int value { get; set; } /// /// 不指定数值构造实例 /// protected henum(string name) { this.name = name; this.value = ++counter; members.add(this); if (!hashtable.containskey(this.value)) { hashtable.add(this.value, this); } } /// /// 指定数值构造实例 /// protected henum(string name, int value) : this(name) { this.value = value; counter = value; } /// /// 向string转换 /// /// public override string tostring() { return this.name.tostring(); } /// /// 显式强制从int转换 /// /// /// public static explicit operator henum(int i) { if (hashtable.containskey(i)) { return (henum)members[i]; } return new henum(i.tostring(), i); } /// /// 显式强制向int转换 /// /// /// public static explicit operator int(henum e) { return e.value; } public static void foreach(action 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,
话说回来,此类还有诸多不足,充其量只能算是一个实验品,想要真正走向实用,还有些工作要做。在此发布,纪念此次实验及成果。