测试接口是否等于类型参数 [英] Test if an interface equals a type parameter
问题描述
我有一个可以存放接口的列表。
我想要一个删除函数,它只删除支持特定接口的项目。
类型
TMyList< T:IFoo> = class
procedure删除(const Item:T);超载;
程序删除< I:IBar>(const Item:T);超载;
end;
procedure TMyList< T> .Remove< I>(const Item:T);
开始
支持(Item,I)然后Remove(Item);
end;
E2250没有可以调用的'Supports'的重载版本与这些论点
有没有办法可以做到这一点?
首先,这两个接口应该有一个GUID声明(如果你还没有这样做)。
type
IBar = interface
['{08C764E8-3EF4-42A7-94B7-8D1C5371DF25}']
end;
IFoo =接口
['{30B9440D-A012-4C7D-8422-A80D7E18F4E5}']
end;
然后,您应该可以将呼叫更改为支持:
使用System.TypInfo;
函数TMyList< T> .Remove< I>(const Item:T);
begin
// if支持(Item,I)然后Remove(Item);
支持(Item,GetTypeData(TypeInfo(I))^。GUID)然后Remove(Item);
// ...
end;
虽然编译器不知道I是一种接口类型,但是您可以这样做 - 因为你制约了它。因此,从TypeData中为I提取GUID是安全的。
$ b
泛型类型约束(类,或接口或记录)不 在引用或使用的代码中声明或优化泛型参数的数据类型。
类型
IBar =接口
['{08C764E8-3EF4-42A7-94B7-8D1C5371DF25}']
end;
IFoo =接口
['{30B9440D-A012-4C7D-8422-A80D7E18F4E5}']
end;
IFoo1 =接口(IFoo)
['{6C3D06C9-C0B7-45CD-80F2-45123ECC5E9C}']
end;
IFoo2 =接口(IFoo)
['{9C3AB5F7-E88C-4620-AFC5-B83340048531}']
end;
TMyList< T:IFoo> = class
end;
< T:IFoo>约束将允许这些:
var
L:TMyList< IFoo>;
L:TMyList< IFoo1>;
L:TMyList< IFoo2>;
但这不是:
L:TMyList< IBar> ;;
最重要的是,在3个有效的扩展中,T成为一种界面类型。它在编译器的眼中仍然是泛型的或类型未知的。
构造函数约束是这个规则的一个例外。它需要泛型参数为类类型,但更重要的是,它允许通过无参数构造函数实例化目标类,而无需类型转换。
类型
TMyClass = class
构造函数Create;
程序DoSomething;
end;
构造函数TMyClass.Create;
begin
end;
过程TMyClass.DoSomething;
begin
end;
类型
TMyGeneric2< T:构造函数> = class
过程执行;
end;
procedure TMyGeneric2< T> ;.Perform;
var
x:T;
begin
x:= T.Create; //这是允许的...
x.DoSomething; // ...但这不是。
end;
当您使用泛型类型参数约束时,不解析类型的通用参数。您只需设置一些规则,供编译器在使用该泛型类型时遵循。
I have a list that can hold interfaces.
I want to have a remove function that only deletes items that support a particular interface.
type
TMyList<T: IFoo> = class
procedure Remove(const Item: T); overload;
procedure Remove<I: IBar>(const Item: T); overload;
end;
procedure TMyList<T>.Remove<I>(const Item: T);
begin
if Supports(Item, I) then Remove(Item);
end;
E2250 There is no overloaded version of 'Supports' that can be called with these arguments
Is there a way in which this can be done?
First, the two interfaces should have a GUID declared with them (If you haven't done this already).
type
IBar = interface
['{08C764E8-3EF4-42A7-94B7-8D1C5371DF25}']
end;
IFoo = interface
['{30B9440D-A012-4C7D-8422-A80D7E18F4E5}']
end;
Then, you should be able to change the call to "supports" to this:
uses System.TypInfo;
function TMyList<T>.Remove<I>(const Item: T);
begin
//if Supports(Item, I) then Remove(Item);
if Supports(Item, GetTypeData( TypeInfo(I) )^.GUID) then Remove(Item);
// ...
end;
While the compiler does not "know" that "I" is an interface type, you do - because you constrained it. So, it's safe to extract the GUID out of the TypeData for "I".
Generic type constraints (either class, or interface or record) do not declare or refine the data type of the generic parameter in the code where that are referenced or consumed. Rather, they simply allow the compiler to restrict how the generic type may be used.
type
IBar = interface
['{08C764E8-3EF4-42A7-94B7-8D1C5371DF25}']
end;
IFoo = interface
['{30B9440D-A012-4C7D-8422-A80D7E18F4E5}']
end;
IFoo1 = interface(IFoo)
['{6C3D06C9-C0B7-45CD-80F2-45123ECC5E9C}']
end;
IFoo2 = interface(IFoo)
['{9C3AB5F7-E88C-4620-AFC5-B83340048531}']
end;
TMyList<T: IFoo> = class
end;
The < T:IFoo > constraint will allow these:
var
L : TMyList<IFoo>;
L : TMyList<IFoo1>;
L : TMyList<IFoo2>;
But not this:
L : TMyList<IBar>;
And, most importantly, in the 3 valid expansions, "T" does not become an interface type. It is still generic or "type-unknown" in the compiler's eyes.
The "constructor" constraint is the one exception to this rule. It will require the generic parameter to be a class type but more importantly, it allows instantiation of the target class through a parameter-less constructor without type casting.
type
TMyClass = class
constructor Create;
procedure DoSomething;
end;
constructor TMyClass.Create;
begin
end;
procedure TMyClass.DoSomething;
begin
end;
type
TMyGeneric2<T:constructor> = class
procedure Perform;
end;
procedure TMyGeneric2<T>.Perform;
var
x : T;
begin
x := T.Create; // This is allowed...
x.DoSomething; // ...but this is not.
end;
When you use generic type parameter constraints, you are not resolving the type of the generic parameter. You are merely setting-up some rules for the compiler to follow when that generic type is consumed.
这篇关于测试接口是否等于类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!