工作中許多代碼中用到枚舉(enum),更用到了需要繼承的枚舉,由於C#的枚舉不允許被繼承(但允許繼承自int/float等類型,這個不是我要的,在此不討論)。
我實現了一個可以繼承的模擬枚舉,在此與各位分享。
於是我努力制造出可以繼承的枚舉,確切地說是可以繼承的“仿枚舉”。
首先要仿System.Enum造一個仿它的地位的類,以“操控一切”。它也是一切可繼承枚舉的鼻祖。
此類要承擔諸多功能:
1.與int/string之間的相互轉換
2.支持實例(靜態屬性)指定或不指定數值
3.一些輔助的功能,如比較大小等
4.一些方便使用的功能,如ForEach方法
5.像string類(class)一樣,表現出值傳遞的效果
2 using System.Collections;
3 using System.Collections.Generic;
4
5 namespace HeritableEnum
6 {
7 public class HEnum : IComparable<HEnum>, IEquatable<HEnum>
8 {
9 static int counter = - 1; // 默認數值計數器
10 private static Hashtable hashTable = new Hashtable(); // 不重復數值集合
11 protected static List<HEnum> members = new List<HEnum>(); // 所有實例集合
12 private string Name { get; set; }
13 private int Value { get; set; }
14
15 /// <summary>
16 /// 不指定數值構造實例
17 /// </summary>
18 protected HEnum( string name)
19 {
20 this.Name = name;
21 this.Value = ++counter;
22 members.Add( this);
23 if (!hashTable.ContainsKey( this.Value))
24 {
25 hashTable.Add( this.Value, this);
26 }
27 }
28
29 /// <summary>
30 /// 指定數值構造實例
31 /// </summary>
32 protected HEnum( string name, int value)
33 : this(name)
34 {
35 this.Value = value;
36 counter = value;
37 }
38
39 /// <summary>
40 /// 向string轉換
41 /// </summary>
42 /// <returns></returns>
43 public override string ToString()
44 {
45 return this.Name.ToString();
46 }
47
48 /// <summary>
49 /// 顯式強制從int轉換
50 /// </summary>
51 /// <param name="i"></param>
52 /// <returns></returns>
53 public static explicit operator HEnum( int i)
54 {
55 if (hashTable.ContainsKey(i))
56 {
57 return (HEnum)members[i];
58 }
59 return new HEnum(i.ToString(), i);
60 }
61
62 /// <summary>
63 /// 顯式強制向int轉換
64 /// </summary>
65 /// <param name="e"></param>
66 /// <returns></returns>
67 public static explicit operator int(HEnum e)
68 {
69 return e.Value;
70 }
71
72 public static void ForEach(Action<HEnum> action)
73 {
74 foreach (HEnum item in members)
75 {
76 action(item);
77 }
78 }
79
80 public int CompareTo(HEnum other)
81 {
82 return this.Value.CompareTo(other.Value);
83 }
84
85 public bool Equals(HEnum other)
86 {
87 return this.Value.Equals(other.Value);
88 }
89
90 public override bool Equals( object obj)
91 {
92 if (!(obj is HEnum))
93 return false;
94 return this.Value == ((HEnum)obj).Value;
95 }
96
97 public override int GetHashCode()
98 {
99 HEnum std = (HEnum)hashTable[ this.Value];
100 if (std.Name == this.Name)
101 return base.GetHashCode();
102 return std.GetHashCode();
103 }
104
105 public static bool operator !=(HEnum e1, HEnum e2)
106 {
107 return e1.Value != e2.Value;
108 }
109
110 public static bool operator <(HEnum e1, HEnum e2)
111 {
112 return e1.Value < e2.Value;
113 }
114
115 public static bool operator <=(HEnum e1, HEnum e2)
116 {
117 return e1.Value <= e2.Value;
118 }
119
120 public static bool operator ==(HEnum e1, HEnum e2)
121 {
122 return e1.Value == e2.Value;
123 }
124
125 public static bool operator >(HEnum e1, HEnum e2)
126 {
127 return e1.Value > e2.Value;
128 }
129
130 public static bool operator >=(HEnum e1, HEnum e2)
131 {
132 return e1.Value >= e2.Value;
133 }
134 }
135 }
經過時間跨度很長中的N次嘗試后,寫成了上面這個樣子,實現了最基本的功能。ForEach后面都是直接或間接為了“比較大小”要寫的方法。
值得強調的是此類的所有構造方法必須是protected,以防止在類之外構造實例。它的子類也必須這樣,以下是用於演示的子類:
{
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繼承,模擬以下的代碼
{
A,
B = 2,
C = 2,
D
}
再有一個子類從EnumUse1繼承:
{
protected EnumUse2( string name) : base(name) { }
protected EnumUse2( string name, int value) : base(name, value) { }
public static EnumUse2 E = new EnumUse2( " E ");
}
用起來跟系統原生的enum很像
{
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,
話說回來,此類還有諸多不足,充其量只能算是一個實驗品,想要真正走向實用,還有些工作要做。在此發布,紀念此次實驗及成果。