用泛型实现对枚举的通用处理
写代码的时候遇到一个问题,想写一个通用方法来实现对枚举的类型的操作,如获取枚举的项的列表,获取一个枚举值的索引等等,
本来以为很简单,写一个函数:
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;
通过这次尝试,加深了对泛型的理解。