zoukankan      html  css  js  c++  java
  • 用泛型实现对枚举的通用处理

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

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

    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;

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

  • 相关阅读:
    设计模式--22、状态模式
    设计模式--21、备忘录模式
    设计模式--20、迭代器模式
    关于分布式事务、两阶段提交协议、三阶提交协议
    分布式系统的一致性探讨
    分布式系统的BASE理论
    分布式系统的CAP理论
    Kafka集群环境搭建
    Elasticsearch插件head的安装(有坑)
    centos6 x64安装elasticsearch5.5.2启动报错
  • 原文地址:https://www.cnblogs.com/codingnote/p/3979963.html
Copyright © 2011-2022 走看看