利用C#实现可以继承的"枚举"
作者:BillySir 发布时间:2021-08-08 20:55:50
工作中许多代码中用到枚举(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,
话说回来,此类还有诸多不足,充其量只能算是一个实验品,想要真正走向实用,还有些工作要做。在此发布,纪念此次实验及成果。
来源:https://www.cnblogs.com/BillySir/archive/2012/02/15/2353395.html
猜你喜欢
- 首先来看看Map集合获取元素的三种常见方法keySet()、values()、entrySet()1. values():返回map集合的所
- 前言:项目是使用Java swing开发,可实现基础数据维护用户登录、系统首页酒店信息管理、主要模块是开房管理、退房管理、房间信息管理、顾客
- 前言看标题好像很简单的样子,但是针对使用jar包发布SpringBoot项目就不一样了。当你使用tomcat发布项目的时候,上传文件存放会变
- 一、Spring Boot的特点首先我们要知道 Spring Boot 在底层已经为我们添加好了很多依赖。比如我们常用的Tomcat,Spr
- 一、定义实体类Person,封装生成的数据package net.dc.test;public class Person { private
- 目录1、通过session中的token验证步骤1:创建自定义注解步骤2:创建自定义 * (@slf4j是lombok的注解)步骤3:将自定
- Web基础和HTTP协议┌─────────┐┌─────────┐
- 前言现在开发大部分都是服务化或者微服务,数据交换都是跨服务的,这里记录java调取其他接口的方法,下面话不多说了,来一起看看详细的介绍吧。j
- 软件需求VS2019社区版、win10操作系统、opencv4.1.0VS2019社区版(免费) 下载地址OpenCV4.1.0 下载地址配
- 1 概念方面List是接口,ArrayList是List接口的一个实现类2 初始化方面2.1 List2.1.1 错误写 * ist list
- 实现多线程的方式:实现多线程的方式有多种,这里只列举两种常用的,而第一种继承Thread的方式无法实现多窗口卖票。一,继承Thread方式:
- 本文为大家分享了Java实现班级管理系统的具体代码,供大家参考,具体内容如下需求:班级管理系统功能:对学生的信息进行管理1 登录系统 &nb
- //字符串的内存驻留机制 public static v
- 1.概述在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要
- 本文讲述了Java开发人员需知的十大戒律。分享给大家供大家参考,具体如下:作为一个Java开发人员提高自己代码的质量,可维护性,是个恒久不变
- 本文实例完成人机猜拳互动游戏的开发,供大家参考,具体内容如下阶段一:实验——分析业务,创建用户类1.分析业务,抽象出类、类的特征和行为2.创
- Feign Client 超时时间配置不生效解决方案Feign Client 的 connectTimeout 和 readTimeout
- 在用java的io流读写文件时,总是被它的各种流能得很混乱,有40多个类,理清啦,过一段时间又混乱啦,决定整理一下!以防再忘Java输入/输
- Java内部类一、 含义在Java编程语言里,程序是由类(class)构建而成的。在一个类的内部也可以声明类,我们把这样的类叫做内部类。二、
- java 中 System.out.println()和System.out.write()的区别.这两个函数一个是System