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

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

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

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;

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值