利用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,

话说回来,此类还有诸多不足,充其量只能算是一个实验品,想要真正走向实用,还有些工作要做。在此发布,纪念此次实验及成果。

相关文章