使用Supports()函数和通用接口类型

时间:2010-12-11 18:34:50

标签: delphi generics interface

我刚刚尝试在Delphi 2009中首次使用泛型,并且对如何使用泛型类型作为Supports函数的输入感到困惑,该函数用于查看对象是否实现给定的接口。我已经创建了一个小样本来说明问题。

给出以下类型和效用函数:

IMyInterface = interface
['{60F37191-5B95-45BC-8C14-76633826889E}']
end;

TMyObject = class(TInterfacedObject, IMyInterface)
end;

class function TFunctions.GetInterface<T>(myObject: TObject): T;
var
  specificInterface: T;
begin
  // This would compile, but looses the generic capability
  //Supports(myObject, IMyInterface, specificInterface);

  // This results in compile errors
  Supports(myObject, T, specificInterface);

  result := specificInterface;
end;

以及以下代码段:

class procedure TFunctions.Test;
var
  myObject: TMyObject;
  myInterface: IMyInterface;
begin
  myObject := TMyObject.Create;

  myInterface := GetInterface<IMyInterface>(myObject);
end;

我希望没有问题,但我得到以下编译时错误:

  

[DCC Error] GenericExample.pas(37):E2029'('预期但','发现   [DCC错误] GenericExample.pas(37):E2014期望语句,但找到类型'T'的表达式

当用作函数的实际参数时,我不确定编译器期望我用T做什么。

我搜索了很多,并且无法解决这个问题。我的一部分怀疑如果我能理解在编译期间接口名称如何转换为IID:TGUID类型,当使用具体的接口名称时,我可以取得一些进展,但这也避开了我。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:10)

无法保证T具有与之关联的GUID,并且语言中没有任何方法可以在类型参数上写入约束来进行保证。

编译器在符号表中查找名称,获取编译器表示接口的数据结构,并检查GUID的相应字段,将接口名称转换为GUID。但泛型不像C ++模板;它们需要进行编译和类型检查,并且已知可用于任何有效的类型参数,这意味着在其声明中约束type参数。

您可以使用RTTI(首先检查T确实代表一个接口)使用GetTypeData(TypeInfo(T))^.Guid之类的内容获取GUID,然后将GUID传递给Supports

答案 1 :(得分:1)

你为什么甚至打扰?

要使用此TFunctions.GetInterface,您需要:

  • 界面
  • 对象参考

如果你有那些,那么你可以直接调用Supports():

  intf := TFunctions.GetInterface<IMyInterface>(myObject);

完全等同于:

  Supports(IMyInterface, myObject, intf);

在这里使用泛型是浪费时间和精力,并且真正回答“为什么这样做?”的问题。

只是让事情变得更难阅读(仿制药一般都是这样)并且使用起来比较麻烦。

支持()返回一个方便的布尔值来表示成功/失败,您必须使用包装器单独测试:

  intf := TFunctions.GetInterface<IMyInterface>(myObject);
  if Assigned(intf) then
    // ...

  if Supports(IMyInterface, myObject, intf) then
    // We can use intf

在创建功能包装时,通常情况下结果是可读性或可用性方面的改进。

imho这两项都失败了,你应该坚持使用支持()功能本身。