用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 { getset; }
 13         private int Value { getset; }
 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");
}

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,

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

 

posted @ 2012-02-15 23:16  BillySir  阅读(17181)  评论(5编辑  收藏  举报