我对匿名方法类型使用什么通用约束?

时间:2014-07-17 21:44:10

标签: delphi generics anonymous-methods

我想声明这样的通用记录:

type
  TMyDelegate<T: constraint> = record
  private
    fDelegate: T;
  public
    class operator Implicit(a: T): TMyDelegate;
    class operator Implicit(A: TMyDelegate: T);
  end;

我想将T限制为reference to procedure/function。 (越多越好)。

我试过这个,但它没有编译:

program Project3;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type

  TProc1 = reference to procedure(a: Integer);
  TProc2 = reference to procedure(b: TObject);

  TTest<T: TProc1, TProc2> = record
  private
    fData: T;
  public
    class operator Implicit(a: T): TTest<T>;
    class operator Implicit(a: TTest<T>): T;
  end;

  { TTest<T> }

class operator TTest<T>.Implicit(a: T): TTest<T>;
begin
  Result.fData:= a;
end;

class operator TTest<T>.Implicit(a: TTest<T>): T;
begin
  Result:= a.fData;
end;

var
  Delegate1: TProc1;
  Delegate2: TProc2;

var
  MyTest1: TTest<TProc1>;  <<-- error
  MyTest2: TTest<TProc2>;

begin
  MyTest1:=
    procedure(a: Integer)
    begin
      WriteLn(IntToStr(a));
    end;
end.

这会产生编译错误:

  

[dcc32错误] Project3.dpr(39):E2514类型参数'T'必须支持接口'TProc2'

有没有办法将通用类型约束为(一系列)匿名类型?

3 个答案:

答案 0 :(得分:5)

大卫的答案是正确的,但解决这个问题可能有所帮助:

program Project51;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type
  TTest<T> = record
  type
    TProcT = reference to procedure(a: T);
  private
    fData: TProcT;
  public
    class operator Implicit(a: TProcT): TTest<T>;
    class operator Implicit(a: TTest<T>): TProcT;
  end;

  { TTest<T> }

class operator TTest<T>.Implicit(a: TProcT): TTest<T>;
begin
  Result.fData:= a;
end;

class operator TTest<T>.Implicit(a: TTest<T>): TProcT;
begin
  Result:= a.fData;
end;

var
  MyTest1: TTest<Integer>;
  MyTest2: TTest<TObject>;

begin
  MyTest1:=
    procedure(a: Integer)
    begin
      WriteLn(IntToStr(a));
    end;
  MyTest2:=
    procedure(a: TObject)
    begin
      WriteLn(a.ClassName);
    end;
end.

答案 1 :(得分:3)

无法指定此类约束。可能的限制是:

  • 值类型。
  • 类,源自特定的祖先。
  • 接口,源自特定的祖先。
  • 无参数构造函数。

文档中介绍了这一点:http://docwiki.embarcadero.com/RADStudio/en/Constraints_in_Generics

文档没有说明的是引用过程类型计为接口。这就是你的泛型类型使用该约束进行编译的原因。但这对你没有任何用处。因为引用过程类型没有继承。因此,唯一可以满足特定参考过程类型约束的是特定类型的东西。

实际上您的类型无法实例化。这是因为约束

T: TProc1, TProc2

指定T支持这两个引用过程接口。没有什么能做到的。没有什么可以同时支持TProc1TProc2

答案 2 :(得分:2)

感谢GrayMatter和David我已经找到解决问题的方法。

解决方案是重新定义匿名过程以适应约束。

定义了以下功能。

TA = reference to procedure(const &In, &Out: TArray<TOmniValue>);
TB = reference to procedure(const &In, &Out: TArray<IOmniBlockingCollection>);
TC = .....

诀窍是重新定义这样的方法:

program Project3;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

type
  IData<Tin, Tout> = interface
    ['{D2132F82-CAA9-4F90-83A9-9EFD6221ABE2}']
    function GetInput: TArray<TIn>;
    function GetOutput: TArray<Tout>;
  end;

  TData<TIn, TOut> = class(TInterfacedObject, IData<Tin, Tout>)
  private
    fInput: TArray<Tin>;
    fOutput: TArray<Tout>;
  public
    constructor Create(const input: TArray<TIn>; const output: TArray<TOut>);
    function GetInput: TArray<Tin>;
    function GetOutput: TArray<Tout>;
  end;

  TDelegate<Tin, Tout> = reference to procedure(const Data: IData<TIn, TOut>);

{ TSimpleData }

constructor TData<TIn, TOut>.Create(const input: TArray<TIn>;
  const output: TArray<TOut>);
begin
  finput:= input;
  foutput:= output;
end;

function TData<Tin, Tout>.GetInput: TArray<Tin>;
begin
  Result:= fInput;
end;

function TData<Tin, Tout>.GetOutput: TArray<TOut>;
begin
  Result:= fOutput;
end;

var
  IntegerDelegate: TDelegate<Integer, Integer>;
  input, output: TArray<Integer>;
  i: Integer;
  Data: TData<Integer, Integer>;

begin
  IntegerDelegate:= procedure(const Data: IData<Integer, Integer>)
  var
    i: Integer;
    input: TArray<Integer>;
  begin
    input:= Data.GetInput;
    for i:= 0 to High(input) do begin
      Data.GetOutput[i]:= input[i]+10;
    end;
  end;
  SetLength(input,10);
  SetLength(output, Length(input));
  for i:= Low(input) to High(input) do begin
    input[i]:= i;
  end;
  Data:= TData<Integer, Integer>.Create(input, output);
  IntegerDelegate(Data);
  for i in output do Writeln(i);
  Readln;
end.

我现在可以将委托限制为允许的类型(或多或少)。