用C#制造可以继承的“枚举”
工作中许多代码中用到枚举(enum),更用到了需要继承的枚举,由于C#的枚举不允许被继承(但允许继承自int/float等类型,这个不是我要的,在此不讨论)。
我实现了一个可以继承的模拟枚举,在此与各位分享。
于是我努力制造出可以继承的枚举,确切地说是可以继承的“仿枚举”。
首先要仿System.Enum造一个仿它的地位的类,以“操控一切”。它也是一切可继承枚举的鼻祖。
此类要承担诸多功能:
1.与int/string之间的相互转换
2.支持实例(静态属性)指定或不指定数值
3.一些辅助的功能,如比较大小等
4.一些方便使用的功能,如ForEach方法
5.像string类(class)一样,表现出值传递的效果
1 using System;
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 }
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,以防止在类之外构造实例。它的子类也必须这样,以下是用于演示的子类:
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");
}
{
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
}
{
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");
}
{
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());
}
}
{
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,
话说回来,此类还有诸多不足,充其量只能算是一个实验品,想要真正走向实用,还有些工作要做。在此发布,纪念此次实验及成果。
博主简介:佘焕敏(shé),洋名 Billy Sir。
关注编程基础技术,并致力于研究软件的自动化生成。 对编程规范化、面向对象的极致使用也有着浓厚的兴趣。 同时非常希望能够写程序到65岁。
只有工匠精神,才能把常人觉得单调乏味的代码,当作作品雕刻成艺术品。
重点:这里几乎每一篇文章,都是我认真创作的,凝结了心血。写作从来都不是一件容易的事,对从小语文不好的我而言,是难上加难。而且,你发现没有,文中没有广告。这篇文章介绍了为什么要写这些文章。

【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性