寫代碼的時候遇到一個問題,想寫一個通用方法來實現對枚舉的類型的操做,如獲取枚舉的項的列表,獲取一個枚舉值的索引等等,函數
原本覺得很簡單,寫一個函數:spa
function GetEnumNames(枚舉類): TArray<string>code
結果發現這個參數怎麼搞也搞不對,不知道傳一個什麼樣的參數能夠支持全部枚舉類型,由於函數內會用TypeInfo。blog
後來想到用泛型來傳入枚舉類來處理,果真成功了。索引
/// <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;
經過此次嘗試,加深了對泛型的理解。string