【问题标题】:Delphi 2009 generics compilation problemDelphi 2009 泛型编译问题
【发布时间】:2008-11-06 23:13:10
【问题描述】:

我正在查看 Delphi 2009 试用版,但马上就遇到了泛型问题。

以下代码无法编译,我一点也不知道为什么它为 Equals() 方法提供 E2015:

type
  TPrimaryKey<T> = class(TObject)
  strict private
    fValue: T;
  public
    constructor Create(AValue: T);
    function Equals(Obj: TObject): boolean; override;
    function GetValue: T;
  end;

constructor TPrimaryKey<T>.Create(AValue: T);
begin
  inherited Create;
  fValue := AValue;
end;

function TPrimaryKey<T>.Equals(Obj: TObject): boolean;
begin
  Result := (Obj <> nil) and (Obj is TPrimaryKey<T>)
    and (TPrimaryKey<T>(Obj).GetValue = fValue);
end;

function TPrimaryKey<T>.GetValue: T;
begin
  Result := fValue;
end;

为什么编译器认为fValue和GetValue()的结果不能比较?

【问题讨论】:

    标签: delphi generics delphi-2009


    【解决方案1】:

    如果 T 是一个字符串呢?如果是 TSize 记录呢?

    如果没有约束 T(例如,使用 ),您无法确定比较是否有意义。

    如果您想比较 T 类型的两个值,则可以使用 Generics.Defaults 单元并使用:

    TEqualityComparer<T>.Default.Equals(x, y)
    

    比较 T 类型的值 x 和 y。

    【讨论】:

    • 我不明白你的第一句话(我相信代码不会那样做),但是用你的 TEqualityComparer 代码替换 Equals() 中的相等检查可以解决我的问题,所以谢谢。不幸的是,文档和示例在 Delphi 2009 中再次令人失望:-(
    【解决方案2】:

    您不能将运算符与无类型的泛型一起使用。请参阅here 进行讨论。

    如果您将其更改为,它将编译:

    TPrimaryKey<T: class> = class(TObject)
    

    【讨论】:

    • 感谢您的链接,以下内容让我大开眼界:“泛型是在专门用于最终类型之前编译的”我认为 C++ 模板是错误的,Delphi 泛型不是解决我的问题。
    【解决方案3】:

    我认为最初的发布者正试图围绕简单类型(整数、双精度等)创建一个对象包装器,因此将 T 限制为 Class 可能无法满足他的要求。

    【讨论】:

    • 确实如此。但看起来在 Delphi 2009 中实现的泛型并不是我希望的那样。
    • 问题是,不像.net,在delphi中,简单类型不是对象。
    【解决方案4】:

    编译器无法确定两个“T”是否相同。但是通过一个小技巧,你可以让它发挥作用:

    type
      TPrimaryKey<T> = class(TObject)
      public
        type
          TCompare<T1> = reference to function(const A1, A2: TPrimaryKey<T1>): Boolean;
      private
        fValue: T;
        fCompare : TCompare<T>;
      public
        constructor Create(AValue: T; ACompare: TCompare<T>);
        function Equals(Obj: TPrimaryKey<T>): Boolean; reintroduce;
        function GetValue: T;
        function CreateNew(const AValue: T): TPrimaryKey<T>;
    
      end;
    
    constructor TPrimaryKey<T>.Create(AValue: T; ACompare: TCompare<T>);
    begin
      inherited Create;
      fValue := AValue;
      fCompare := ACompare;
    end;
    
    function TPrimaryKey<T>.Equals(Obj: TPrimaryKey<T>): Boolean;
    begin
      Result := FCompare(self, Obj);
    end;
    
    function TPrimaryKey<T>.GetValue: T;
    begin
      Result := fValue;
    end;
    
    function TPrimaryKey<T>.CreateNew(const AValue: T): TPrimaryKey<T>;
    begin
      Result := TPrimaryKey<T>.Create(AValue, FCompare);
    end;
    

    您使用以下方法对其进行实例化:

    var
      p1, p2 : TPrimaryKey<Integer>;
    begin
      p1 := TPrimaryKey<Integer>.Create(10,
        function(const A1, A2: TPrimaryKey<Integer>): Boolean
        begin
          Result := (A1<>nil) and (A2<>nil) and (A1.GetValue=A2.GetValue);
        end);
      p2 := p1.CreateNew(10);
    
      p1.Equals(p2);
    end;
    

    【讨论】:

      猜你喜欢
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-04
      相关资源
      最近更新 更多