【问题标题】:Delphi - Generics type constraint ordinal typesDelphi - 泛型类型约束序数类型
【发布时间】:2015-02-04 14:17:07
【问题描述】:

我想为 Integer 和 string 类型绑定类型 T:

interface

type
  MyFactory<T> = class
  public
    function createGenerator<T:Integer,string>:IGenerator<T>;
  end;

但是编译器给出:'(..) E2510 Type 'Integer' is not a valid constraint'。如何将类型 T 限制为整数或字符串?或者这是因为我使用的是序数类型而导致的问题?

【问题讨论】:

    标签: delphi generics delphi-xe7


    【解决方案1】:

    Delphi 泛型不支持序数或字符串类型约束。

    只有允许的约束是

    • 零、一种或多种接口类型
    • 零或一类类型
    • 保留字“constructor”、“class”或“record”

    Delphi Constraints in Generics

    我只能猜测你到底想要完成什么,但下面的代码可能会给你一些想法

      IGenerator<T> = interface
        function Generate: T;
      end;
    
      TStringGenerator = class(TInterfacedObject, IGenerator<string>)
      public
        function Generate: string;
      end;
    
      TIntegerGenerator = class(TInterfacedObject, IGenerator<integer>)
      public
        function Generate: integer;
      end;
    
      MyFactory<T> = class
      public
        class function createGenerator<T>: IGenerator<T>;
      end;
    
    class function MyFactory<T>.createGenerator<T>: IGenerator<T>;
    var
      gs: IGenerator<string>;
      gi: IGenerator<integer>;
    begin
      if TypeInfo(T) = TypeInfo(string) then
        begin
          gs := TStringGenerator.Create;
          Result := IGenerator<T>(gs);
        end
      else
      if TypeInfo(T) = TypeInfo(integer) then
        begin
          gi := TIntegerGenerator.Create;
          Result := IGenerator<T>(gi);
        end
      else Result := nil;
    end;
    
    function TIntegerGenerator.Generate: integer;
    begin
      Result := 10;
    end;
    
    function TStringGenerator.Generate: string;
    begin
      Result := 'abc';
    end;
    
    var
      i: integer;
      s: string;
    
      i := MyFactory<integer>.createGenerator<integer>.generate;
      s := MyFactory<string>.createGenerator<string>.generate;
    

    TTypeKind 也可以用来代替TypeInfo 来确定类型。主要区别在于TypeInfo 为您提供了使用的确切类型,而TTypeKind 涵盖了属于特定类别的所有类型。虽然TTypeKind 提供了更大的灵活性,但如果代码依赖于类型转换,则应谨慎使用。例如tkInteger 涵盖integerbyte 类型,类型转换可能会导致错误。

    class function MyFactory<T>.createGenerator<T>: IGenerator<T>;
    var
      gs: IGenerator<string>;
      gi: IGenerator<integer>;
    begin
      case PTypeInfo(TypeInfo(T)).Kind of
        tkUString :
          begin
            gs := TStringGenerator.Create;
            Result := IGenerator<T>(gs);
          end;
        tkInteger :
          begin
            gi := TIntegerGenerator.Create;
            Result := IGenerator<T>(gi);
          end
        else Result := nil;
      end;
    end;
    

    【讨论】:

    • @TLama 那会很好。这会让读者知道答案现在已经被语言超越了。如果我们链接到特定版本(我编辑是因为原始链接到 XE6 而不是当前版本 XE7),那么未来的读者就会错过发现这些发展的机会。
    • GetTypeKind 我认为在这里更合适。
    • @David 取决于代码。 TypeInfo 给出了确切的类型,这对于我的示例中的类型转换很重要。
    • 也许吧。我认为序数的意思是,序数。但也许这意味着integer
    • 请不要调用它2-4次,即使它没有太多开销。您可以在 case 中使用 PTypeInfo(TypeInfo(T)).Kind 或将其分配给 TTypeKind 的局部变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多