【问题标题】:Delphi generic class usage compilation errorDelphi泛型类使用编译错误
【发布时间】:2020-03-04 22:30:58
【问题描述】:

我正在为旧的 Delphi XE 代码库编写一些实用程序代码;为了让事情变得更简单和更安全,我创建了一个方法来包装特定类型的TProc<TReq>(其中TReq 是泛型类类型),通过更广泛的TProc<TObject> 中的参数传递,应该提供给稍后会添加一个第三方组件,以及 TClass(TReq) 和一个额外的字符串参数:

type
  TREvoHostConnectionOptions = record
    // [...]
    procedure OnPush<TReq:class>(const pushMethod: string; const action: TProc<TReq>);
  end;

// [...]

procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
    var
      rec: TRPushHandler;
    begin
      rec.PushMethod := pushMethod;
      rec.PushModel := TClass(TReq);
      rec.Handler :=
        procedure(reqRawModel: TObject)
          var
            reqModel: TReq;
          begin
            // Conversione modello richiesta
            reqModel := reqRawModel as TReq;
            if Assigned(reqRawModel) and not Assigned(reqModel) then
              raise EEvoHostException.Create(Format('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, TClass(TReq).ClassName]));
            // Azione
            if Assigned(action) then
              action(reqModel);
          end;
      PushHandlers.Add(rec);
    end;

前面的方法编译成功,如果像这样调用,会按预期工作(尽管将TObject 作为泛型类型违背了该方法的目的):

opts.OnPush<TObject>('Test', procedure (reqModel: TObject) begin (* ... *) end);

但是,如果在测试表单单元中我使用专门设计的模型类调用它:

  type
    TTestModel = class(TObject)
      strict private
        _a, _b: string;
      public
        property A: string read _a write _a;
        property B: string read _b write _b;
    end;

我在调用单元的一个完全不相关的行(以及完全不同且完全不相关的方法)中收到以下编译器错误:

[DCC 错误] WndMain.pas(96):E2010 不兼容的类型:'TTestModel' 和 'TObject'

* 如果我在同一文件中的其他任何地方引入人工语法错误,则会在正确的行报告该错误。


有什么想法吗?这是一个编译器错误,如果是,有什么办法可以解决它?不幸的是,我无法删除该方法上的 :class 约束,否则在方法内部发生的 TClass(TReq) 转换会引发(逻辑上)另一个关于 TReq 不是受约束的类或接口类型的编译错误。

【问题讨论】:

  • 离题提示:尝试Exception.Create(Format('Error %d', [123])),而不是Exception.CreateFmt('Error %d', [123])
  • 谢谢,我总是忘记 CreateFmt。 :)

标签: delphi generics delphi-xe


【解决方案1】:

经过进一步排查,问题似乎是方法中as转换引起的,虽然报错文件了。

这样改方法好像解决了:

procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
    var
      rec: TRPushHandler;
    begin
      rec.PushMethod := pushMethod;
      rec.PushModel := TClass(TReq);
      rec.Handler :=
        procedure(reqRawModel: TObject)
          var
            reqModel: TReq;
          begin
            // Conversione modello richiesta
            if Assigned(reqRawModel) and not reqRawModel.ClassType.InheritsFrom(rec.PushModel) then
              raise EEvoHostException.CreateFmt('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, rec.PushModel.ClassName]);
            // Azione
            if Assigned(action) then
              action(TReq(reqModel));
          end;
      PushHandlers.Add(rec);
    end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    相关资源
    最近更新 更多