我想声明这样的通用记录:
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'
有没有办法将通用类型约束为(一系列)匿名类型?
答案 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
支持这两个引用过程接口。没有什么能做到的。没有什么可以同时支持TProc1
和TProc2
。
答案 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.
我现在可以将委托限制为允许的类型(或多或少)。