利用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,
話說回來,此類還有諸多不足,充其量只能算是一個實驗品,想要真正走向實用,還有些工作要做。在此發布,紀念此次實驗及成果。