2014-07-17 133 views
4

我想声明一个通用的记录,像这样:我对匿名方法类型使用什么通用约束?

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

我想限制Treference 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 Error] Project3.dpr(39): E2514 Type parameter 'T' must support interface 'TProc2'

有没有办法约束泛型类型(名单)匿名类型?

回答

3

没有办法指定这样的约束。可能的约束是:

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

这是覆盖在文档中:http://docwiki.embarcadero.com/RADStudio/en/Constraints_in_Generics

什么文件也没有说清楚的是,参考程序类型算作接口。这就是为什么你的泛型类型用这个约束来编译的原因。但这对你来说永远不会有任何用处。因为引用过程类型没有继承。因此唯一能够满足特定参考程序类型约束的是某种特定的类型。

事实上,你的类型不能实例化。这是因为约束

T: TProc1, TProc2 

指定T支持这两个基准程序接口。没有什么可以做到的。没有什么可以同时支持TProc1TProc2

+0

我忘记了约束条件AND'ed在一起,而不是OR'ed。 – Johan

+0

事实上,参考程序约束完全没有用处。 –

+0

您可以创建一个类:THack = class(TInterfacedObject,TProc1,TProc2),以满足要求。不知道它的用途是什么,但我猜你可以编译它。 – Johan

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. 
+0

@GreyMatter,这确实需要一段时间来解决我的问题。我可以从那里看到一个解决方案。 – Johan

+0

+1 well said ..... –

+1

鉴于System.Sysutils声明'TProc =引用过程(Arg1:T);'你可以使用那个而不是自己声明它。 –

2

感谢GrayMatter和大卫,我想出了一个解决问题的办法。

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

定义了以下功能。

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. 

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