用泛型实现对枚举的通用处理

写代码的时候遇到一个问题,想写一个通用方法来实现对枚举的类型的操作,如获取枚举的项的列表,获取一个枚举值的索引等等,

本来以为很简单,写一个函数:

function GetEnumNames(枚举类): TArray<string>

结果发现这个参数怎么搞也搞不对,不知道传一个什么样的参数可以支持所有枚举类型,因为函数内会用TypeInfo。

后来想到用泛型来传入枚举类来处理,果然成功了。

  /// <summary> 针对枚举类型的一组功能函数 </summary>
  TEnumEX<T> = class
  public
    /// <summary> 把字符串转成枚举的值 </summary>
    class function StrToEnumType(const S: string): T; overload;
    /// <summary> 把字符串转成枚举的值 </summary>
    class function StrToEnumType(const S: string; Default: T): T; overload;
    /// <summary> 把枚举的值转成字符串 </summary>
    class function EnumToString(Value: T): string;
    /// <summary> 获取枚举类型的项列表 </summary>
    class function GetEnumNames : TArray<string>;
    /// <summary> 获取枚举值的序号 </summary>
    class function GetEnumOrd(const S: string) : Integer;
  end;

implementation

uses
  RTTI,SysConst,uLayoutConst;

{ TEnumConvert<T> }

class function TEnumEX<T>.EnumToString(Value: T): string;
var
  v: Integer;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkEnumeration:
      case TypInfo.GetTypeData(TypeInfo(T))^.OrdType of
        otUByte, otSByte: v := PByte(@Value)^;
        otUWord, otSWord: v := PWord(@Value)^;
        otULong, otSLong: v := PInteger(@Value)^;
      end;
  else
    raise EInvalidCast.CreateRes(@SInvalidCast);
  end;
  Result := TypInfo.GetEnumName(TypeInfo(T), v);
end;

class function TEnumEX<T>.StrToEnumType(const S: string): T;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkEnumeration:
      case TypInfo.GetTypeData(TypeInfo(T))^.OrdType of
        otUByte, otSByte: PByte(@Result)^ := GetEnumValue(TypeInfo(T), S);
        otUWord, otSWord: PWord(@Result)^ := GetEnumValue(TypeInfo(T), S);
        otULong, otSLong: PInteger(@Result)^ := GetEnumValue(TypeInfo(T), S);
      end;
  else
    raise EInvalidCast.CreateRes(@SInvalidCast);
  end;
end;

class function TEnumEX<T>.GetEnumNames: TArray<string>;
var
  p: PTypeData;
  i: Integer;
  s: String;
  pt: PTypeInfo;
begin
  pt := TypeInfo(T);
  p := GetTypeData(TypeInfo(T));
  SetLength(Result, p.MaxValue+1);
  for i := p.MinValue to p.MaxValue do
  begin
    S := GetEnumName(pt,i);
    Result[i] := S;
  end;
end;

class function TEnumEX<T>.GetEnumOrd(const S: string): Integer;
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkEnumeration:
        Result := GetEnumValue(TypeInfo(T), S);
  else
    raise EInvalidCast.CreateRes(@SInvalidCast);
  end;
end;

class function TEnumEX<T>.StrToEnumType(const S: string; Default: T): T;
begin
  if S <> ‘‘ then begin
    Result := StrToEnumType(S);
  end else begin
    Result := Default;
  end;
end;

调用很简单

var
  s : string;
  ss : TArray<string>;
begin
  inherited;
  ss := TEnumEX<TBIEditUIControl>.GetEnumNames;
  for s in ss do
  begin
    ShowMessage(s);
  end;
end;

通过这次尝试,加深了对泛型的理解。

时间: 2024-08-09 20:07:11

用泛型实现对枚举的通用处理的相关文章

用泛型和反射实现函数通用

使用泛型和反射机制事项函数的通用,写下来,欢迎吐槽 代码示例使用vb. net Imports System.Reflection Module Module1 Sub Main() Dim lst1 As List(Of Person) = New List(Of Person)() Dim lst2 As List(Of Person) = New List(Of Person)() Dim lstT As List(Of Person) = New List(Of Person)() Fo

减少重复工作,通过泛型、反射写一个通用的Ado.net操作数据库的简单orm底层

创建一个基类BaseEntity: public class BaseEntity { [PrimaryKey] public int Id { get; set; } public DateTime CreateTime { get; set; } public Status Status { get; set; } public string Remark { get; set; } } /// <summary> /// 自增主键标识 /// </summary> publi

Swift 中枚举

Swift 中枚举高级用法及实践 字数11017 阅读479 评论0 喜欢20 title: "Swift 中枚举高级用法及实践"date: 2015-11-20tags: [APPVENTURE]categories: [Swift 进阶]permalink: advanced-practical-enum-examples 原文链接=http://appventure.me/2015/10/17/advanced-practical-enum-examples/作者=Benedik

[Effective Java]第六章 枚举和注解

第六章      枚举和注解 30.      用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型,例如一年中的季节或一副牌中的花色.在没引入枚举时,一般是声明一组int常量,每个类型成员一个常量: public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public sta

7-26总结 泛型的用法,以及各种集合的使用.

HashMapput(Key,Value);若无则放入,若有则覆盖替换.int size(); boolean containsKey(key);remove(key); clear(); 泛型<>ArrayList 不用泛型会导致数据无法通用.泛型可以指定数据类型.限制数据类型.例如:list 中add三个元素 3,6,"6".然后计算list的和.就会出现ClasscateException class MyClass<k,v> method1<k&g

学习系列之泛型

一.泛型的是什么 泛型的英文解释为generic,当然我们查询这个单词时,更多的解释是通用的意思,然而有些人会认为明明是通用类型,怎么成泛型了的,其实这两者并不冲突的,泛型本来代表的就是通用类型,只是微软可能有一个比较官方的此来形容自己引入的特性而已,既然泛型是通用的, 那么泛型类型就是通用类型的,即泛型就是一中模子. 在生活中,我们经常会看到模子,像我们平常生活中用的桶子就是一个模子,我们可以用桶子装水,也可以用来装油,牛奶等等,然而把这些都装进桶子里面之后,它们都会具有桶的形状(水,牛奶和油

Effective Java 阅读笔记——枚举和注解

30:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 31:用实例域代替序数 应该给enum添加int域,而不是使用ordinal方法来导出与枚举关联的序数值.(几乎不应使用ordinal方法,除非在编写像EnumMap这样的基于枚举的通用数据结构) //WRONG public enum Fruit{ APPLE, PEAR, ORANGE; public int numberOfFruit(

对java泛型的理解

自jdk1.6之后泛型就被广泛使用了,刚开始也是这么稀里糊涂的学了但是老是搞不懂其中的奥妙,后来随着项目经验的增多慢慢的才体会到了泛型的各种好处,看了不少项目封装的底层才发现原来泛型一般和接口混合使用来满足标准制定和参数多样化这样的代码需求.弄清楚之后我自己也动手实际体验了一下,觉得还是挺简单的.接下来就分享下我学泛型的心得,写的不好大家可以指出来. 1 标识接口 虽然叫标识接口但是这个java类不仅仅局限于interface,class也是OK的,选择接口还是类关键看自己的选择:下面是我定义的

在Spring4中使用通用Mapper

在Spring4中使用通用Mapper Spring4增加了对泛型注入的支持,这个特性对通用Mapper来说,非常的有用,可以说有了这个特性,可以直接在Service中写Mapper<UserInfo> mapper,可以通过BaseService<T>来实现通用的Service. 这篇文档主要讲解通用Mapper在Spring4中的**最佳用法**. 一.在Spring4中配置通用Mapper 和其他里面配置的区别就是在Spring4中可以配置通用Mapper这个类,我们可以把通