代码之家  ›  专栏  ›  技术社区  ›  SeanX

Delphi通用约束问题

  •  2
  • SeanX  · 技术社区  · 17 年前

    我修改基类的范围有限,因为它们需要在D7-D2009和Free Pascal下编译。我需要从TtiObjectList降级,以保持现有的持久性机制正常工作。

    // base class  
    type  
      TtiObjectList = class(TtiObject)
    ...  
    protected  
      function GetItems(i: integer): TtiObject; virtual;  
      procedure SetItems(i: integer; const AValue: TtiObject); virtual;  
    ...  
    public  
      function Add(const AObject : TtiObject): integer; overload; virtual;  
    ...  
    end;  
    

    TtiGenericObjectList<T: TtiObject> = class(TtiObjectList)  
    protected  
      function GetItems(i:integer): T; reintroduce;  
      procedure SetItems(i:integer; const Value: T); reintroduce;  
    public  
      function Add(const AObject: T): integer; reintroduce;  
      property Items[i:integer]: T read GetItems write SetItems; default;  
    end;
    
    implementation
    
    { TtiGenericObjectList<T> }
    
    function TtiGenericObjectList<T>.Add(const AObject: T): integer;  
    var obj: TtiObject;  
    begin  
      obj:= TtiObject(AObject); /// Invalid typecast
      result:= inherited Add(obj);  
    end;  
    
    // alternate add, also fails  
    function TtiGenericObjectList<T>.Add(const AObject: T): integer;  
    begin  
      result:= inherited Add(AObject); /// **There is no overloaded version**
     /// **of 'Add' that can be called with these arguments**  
    end;  
    
    function TtiGenericObjectList<T>.GetItems(i: integer): T;  
    begin  
      result:= T(inherited GetItems(i)); /// **Invalid typecast  **
    end;  
    
    procedure TtiGenericObjectList<T>.SetItems(i: integer; const Value: T);  
    begin  
      inherited SetItems(i, Value);  
    end;  
    

    我遇到的问题是,delphi没有将T视为TtiObject的后代。当我执行以下操作时,会出现无效的排版错误:

    function TtiGenericObjectList<T>.Add(const AObject: T): integer;  
    var obj: TtiObject;  
    begin  
      obj:= TtiObject(AObject); /// **Invalid typecast***
      result:= inherited Add(obj);  
    end;  
    

    如果不进行类型转换,则会出现重载错误,如上面的列表所示。

    肖恩

    5 回复  |  直到 17 年前
        1
  •  2
  •   Mason Wheeler    17 年前

    Delphi 2009编译器在泛型实现中有一些非常严重的缺陷。它并没有像它应该的那样理解约束的含义(Barry Kelly在SO的其他地方承认了这一点;我不记得确切的位置了),跨单元泛型可能会导致非常奇怪的问题。最好的办法是根据具体情况处理这个问题:如果你的代码编译成功,就使用它。如果没有,就回到非泛型实现,直到它们得到修复。希望我们能在不久的将来看到一个修复泛型(和generics.Collections单元)的更新。

        2
  •  2
  •   SeanX    17 年前

    最后,我用以下方法破解了它

    class function TtiGenericObjectList<T>.GenericAsObject(const Value): TObject;
    begin
      Result := TObject(Value);
    end;
    
    class function TtiGenericObjectList<T>.ObjectAsGeneric(const Value): T;
    begin
      Result := T(Value);
    end;
    

    function TtiGenericObjectList<T>.Add(const AObject: T): integer;
    var obj: TtiObject;
    begin
      obj:= TtiObject(GenericAsObject(AObject));
      result:= inherited Add(obj);
      // replaces the following which gets overload errors
    //   result:= inherited Add(TtiObject(AObject));
    end;
    

    function TtiGenericObjectList<T>.GetItems(i: integer): T;
    var obj: TtiObject;
    begin
      obj:= inherited GetItems(i);
      result:= ObjectAsGeneric(obj);
      // replaces the following which gets "Invalid typecast" errors
      // result:= inherited Add(AObject);
    end;
    

    我会稍微清理一下,然后使用它们,直到编译器修复。

        3
  •  1
  •   Cleggy    16 年前

    我最近使用D2010解决了一个类似的问题,这是我想出的代码。

    type
      TGenericList<T: TtiObject> = class(TtiObjectList)
      protected
        function GetItems(AIndex: integer): T; reintroduce;
        procedure SetItems(AIndex: integer; const AValue: T); reintroduce;
      public
        property Items[i:integer]: T read GetItems write SetItems; default;
        function Add(const AObject: T): integer; reintroduce;
      end;
    
    implementation
    
    { TGenericList<T> }
    
    function TGenericList<T>.Add(const AObject: T): integer;
    begin
      Result := inherited Add(TtiObject(AObject));
    end;
    
    function TGenericList<T>.GetItems(AIndex: integer): T;
    begin
      Result := T(inherited GetItems(AIndex));
    end;
    
    procedure TGenericList<T>.SetItems(AIndex: integer; const AValue: T);
    begin
      inherited SetItems(AIndex, AValue);
    end;
    
        4
  •  0
  •   Toon Krijthe    17 年前

    我发现泛型有一些小问题,这对于这样一个新特性来说并不奇怪。而且你正试图混淆编译器;-).

    不幸的是,我手头没有2009年,所以我不能测试,但我有一些建议:

    您是否已查找更新(并安装了更新)?

    您是否尝试过使用as和is运算符:

    obj:= AObject as TtiObject;
    

    TtiGenericList<T: TObject> = class(TtiObjectList)  
    protected  
      function GetItems(i:integer): T; reintroduce;  
      procedure SetItems(i:integer; const Value: T); reintroduce;  
    public  
      function Add(const AObject: T): integer; reintroduce;  
      property Items[i:integer]: T read GetItems write SetItems; default;  
    end;
    
        5
  •  0
  •   Marco van de Voort    13 年前

    (我来到这里是因为一个类似的问题,但在确定问题的同时,我得到了一个不同的解决方案,尽管使用了更新的(XE)Delphi):

    对象 T型。