利用C#实现可以继承的"枚举"

 更新时间:2023年05月22日 10:57:39   作者:BillySir  
工作中许多代码中用到枚举(enum),更用到了需要继承的枚举,由于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<HEnum>, IEquatable<HEnum>
       {
          static int counter = -1;            //默认数值计数器
         private static Hashtable hashTable = new Hashtable();       //不重复数值集合
         protected static List<HEnum> members = new List<HEnum>();   //所有实例集合
         private string Name { get; set; }
          private int Value { get; set; }
        /// <summary>
         /// 不指定数值构造实例
          /// </summary>
         protected HEnum(string name)
         {
             this.Name = name;
             this.Value = ++counter;
              members.Add(this);
             if (!hashTable.ContainsKey(this.Value))
              {
                 hashTable.Add(this.Value, this);
              }
         }
          /// <summary>
         /// 指定数值构造实例
          /// </summary>
         protected HEnum(string name, int value)
             : this(name)
         {
             this.Value = value;
             counter = value;
          }
          /// <summary>
          /// 向string转换
          /// </summary>
          /// <returns></returns>
          public override string ToString()
         {
              return this.Name.ToString();
          }
         /// <summary>
          /// 显式强制从int转换
          /// </summary>
          /// <param name="i"></param>
          /// <returns></returns>
          public static explicit operator HEnum(int i)
          {
              if (hashTable.ContainsKey(i))
             {
                  return (HEnum)members[i];
             }
             return new HEnum(i.ToString(), i);
          }
          /// <summary>
         /// 显式强制向int转换
         /// </summary>
         /// <param name="e"></param>
          /// <returns></returns>
         public static explicit operator int(HEnum e)
         {
             return e.Value;
          }
         public static void ForEach(Action<HEnum> 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,

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

到此这篇关于利用C#实现可以继承的"枚举"的文章就介绍到这了,更多相关C#枚举内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#反射机制介绍

    C#反射机制介绍

    这篇文章介绍了C#的反射机制,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • C#利用Spire.Pdf包实现为PDF添加数字签名

    C#利用Spire.Pdf包实现为PDF添加数字签名

    Spire.PDF for .NET 是一款专业的基于.NET平台的PDF文档控制组件。它能够让开发人员在不使用Adobe Acrobat和其他外部控件的情况下,运用.NET 应用程序创建,阅读,编写和操纵PDF 文档。本文将利用其实现添加数字签名,需要的可以参考一下
    2022-08-08
  • C#利用反射技术实现去掉按钮选中时的边框效果

    C#利用反射技术实现去掉按钮选中时的边框效果

    这篇文章主要介绍了C#利用反射技术实现去掉按钮选中时的边框效果,涉及C#针对窗口的参数设置技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • C#使用Selenium+PhantomJS抓取数据

    C#使用Selenium+PhantomJS抓取数据

    本文主要介绍了C#使用Selenium+PhantomJS抓取数据的方法步骤,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • C#实现文件上传下载Excel文档示例代码

    C#实现文件上传下载Excel文档示例代码

    这篇文章主要介绍了C#实现文件上传下载Excel文档示例代码,需要的朋友可以参考下
    2017-08-08
  • Unity游戏开发之炸弹人游戏的实现

    Unity游戏开发之炸弹人游戏的实现

    大家小时候肯定玩过这款游戏,炸弹人也算是经典中的经典啦。本文将利用Unity模拟实现这一经典游戏,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-03-03
  • C#设计模式实现之生成器模式和责任链模式

    C#设计模式实现之生成器模式和责任链模式

    学完设计模式之后,你就感觉它会慢慢地影响到你写代码的思维方式,下面这篇文章主要给大家介绍了关于C#设计模式实现之生成器模式和责任链模式的相关资料,需要的朋友可以参考下
    2021-08-08
  • C#+MO实现一个道路编辑软件(刚开始)

    C#+MO实现一个道路编辑软件(刚开始)

    C#+MO实现一个道路编辑软件(刚开始)...
    2007-04-04
  • C#遍历删除字符串中重复字符

    C#遍历删除字符串中重复字符

    这篇文章主要介绍了C#遍历删除字符串中重复字符的方法,涉及C#遍历字符串的相关技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • C#批量修改文件后缀的实现方法

    C#批量修改文件后缀的实现方法

    这篇文章主要介绍了C#批量修改文件后缀的实现方法,本文介绍的方法是通用型的,你只要修改读取的文件地址,想要读取的文件后缀名,以及自己想更换的后缀名称即可,感兴趣的小伙伴跟着小伙伴一起来看看吧
    2024-07-07

最新评论