2014-07-17 1 views
4

Je voudrais déclarer un dossier générique comme ceci:Quelle contrainte générique dois-je utiliser pour un type de méthode anonyme?

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

J'aimerais limiter T-reference to procedure/function. (Autant que possible).

J'ai essayé, mais il ne compile pas:

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. 

Cela donne erreur de compilation:

[dcc32 Error] Project3.dpr(39): E2514 Type parameter 'T' must support interface 'TProc2'

est-il un moyen de contraindre un type générique (une liste de) types anonymes?

Répondre

3

Il n'existe aucun moyen de spécifier une telle contrainte. Les contraintes possibles sont:

  • Type de valeur.
  • Classe, dérivée de l'ancêtre spécifique.
  • Interface, dérivée de l'ancêtre spécifique.
  • Constructeur sans paramètre.

Ceci est couvert dans la documentation: http://docwiki.embarcadero.com/RADStudio/en/Constraints_in_Generics

Qu'est-ce que la documentation ne fait pas clair que les types de procédures de référence comptent comme des interfaces. C'est pourquoi votre type générique compile, avec cette contrainte. Mais cela ne vous sert à rien. Parce que les types de procédure de référence n'ont aucun héritage. Et donc la seule chose qui peut répondre à une contrainte de type procédure de référence spécifique est quelque chose de ce type spécifique.

En fait, votre type ne peut pas être instancié. En effet, la contrainte

T: TProc1, TProc2 

précise que T prend en charge ces deux interfaces procédure de référence. Et rien ne peut le faire. Rien ne peut simultanément prendre en charge les deux TProc1 et TProc2.

+0

J'ai oublié que les contraintes sont ET ensemble, pas OR. – Johan

+0

Les contraintes de procédure de référence sont en fait totalement inutiles. –

+0

Vous pouvez créer une classe: THack = class (TInterfacedObject, TProc1, TProc2) répondant aux exigences. Je ne sais pas à quoi cela servirait, mais je suppose que vous pouvez le compiler. – Johan

5

David est la bonne réponse, mais comme un travail autour de quelque chose comme ça peut aider:

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, cela ne va pas un certain temps pour résoudre mon problème. Je peux voir une solution à partir de là. – Johan

+0

+1 bien dit ..... –

+1

Étant donné que System.Sysutils déclare 'TProc = référence à la procédure (Arg1: T);' vous pouvez simplement utiliser celui-ci au lieu de le déclarer vous-même. –

2

Merci à GrayMatter et David, je suis venu avec une solution au problème.

La solution consiste à redéfinir la procédure anonyme pour qu'elle corresponde aux contraintes.

Les fonctions suivantes sont définies.

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

L'astuce consiste à redéfinir les méthodes comme ceci:

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. 

Je peux maintenant limiter le délégué aux types autorisés (plus ou moins).

Questions connexes