您的位置:首页 > 其它

接口引用 如何从一个接口变量取得其接口类型

2011-07-23 17:09 459 查看
http://blog.sina.com.cn/s/blog_5d10e5410100hjna.html

近期在写一个类pascal解释器,对borland的RTTI机制进行了一番学习,了解了borland的RTTI机制,但本人水平有限,在学习有关接口的RTTI过程中,遇到了些无法解释的问题,在这里提出来,大家共同探讨。
首先说明“接口引用”这个概念在delphi中也许不存在,是我相对于“类引用”提出来的。我们知道在delphi 中有类引用的概念,定义方式如TClass = class of TObject,其实质是指向类RTTI的一个指针,我们可以用这个类引用实现好多动态功能。可接口就比较特殊,虽然定义语法和类定义类似,但只是一个空壳,需要通过某个具体的类来实现。虽然接口是一个空壳,但是这个空壳也有RTTI信息,可以通过TypeInfo函数得到。
在VCL中其实也运用了好多 “接口引用”的概念,比如IInterface中的QueryInterface函数,查询接口支持的函数supports等,但在delphi并没有类似“ Interface of Interface”这样的句法来定义一个接口引用,而是使用一个TGUID来完成接口引用的功能。TGUID其实被定义为一个结构类型,delphi的编译器知道如何把TGUID类型转换成接口引用来使用,但对开发者来说却是不公布的。比如:
var
Obj : TObject;
m:TComponent;
ClassRef: TClass;
Intf: IInterface;
IID: TGUID;
begin
obj := TComponent.Create(nil);
ClassRef := obj.ClassType; //对于类变量,我们可以用类函数classType来取得它的类类型。
m := obj as TComponent;
Intf := m; //把M赋给接口变量,因为TComponent实现了IInterface接口。
{
IID := ? intf ;//无法取得接口变量的接口类型?!
}
end;

归结起来,写一个函数,取得一个接口变量的接口类型(GUID):
function GetIntfGUID(AIntf: IInterface):TGUID;
begin
Result := ;//如何实现?和各位继续探讨
end;

解释:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
IFirstIntf=interface
['{64C25101-E002-40EF-92DC-F0DFBF876B1C}']
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;

TFirstIntfClass=class(TInterfacedObject, IFirstIntf)
//IFirstIntf
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;

type
TForm1 = class(TForm)
btnSayHello: TButton;
btnGUIID: TButton;
lst1: TListBox;
btnAllGUID: TButton;
btnIntfaceToGUID: TButton;
procedure btnSayHelloClick(Sender: TObject);
procedure btnGUIIDClick(Sender: TObject);
procedure btnAllGUIDClick(Sender: TObject);
procedure btnIntfaceToGUIDClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

function TFirstIntfClass.GetName;
begin
Result:='Hello World';
end;
procedure TForm1.btnSayHelloClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetName);
finally
FirstIntf:=nil;
end;
end;

function TFirstIntfClass.GetGUID;
begin
if self.GetInterfaceTable.EntryCount>0 then
Result:=GUIDToString(Self.GetInterfaceTable.entries[0].iid)
end;
procedure TForm1.btnGUIIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetGUID);
finally
FirstIntf:=nil;
end;
end;

procedure TForm1.btnAllGUIDClick(Sender: TObject);
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:= 0 to FirstIntfClass.GetInterfaceTable.EntryCount-1 do begin
lst1.Items.Add(GUIDToString(FirstIntfClass.GetInterfaceTable.Entries[I].IID));
end;
FirstIntfClass.Free;
end;

function TFirstIntfClass.GetIntfGUID(AIntf: IInterface):TGUID;
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:=0 to FirstIntfClass.getInterfaceTable.EntryCount-1 do
if FirstIntfClass.GetInterface(FirstIntfClass.getInterfaceTable.Entries[I].IID, AIntf) then begin
Result:=FirstIntfClass.getInterfaceTable.Entries[I].IID;
Exit;
end;
FirstIntfClass.Free;
end;
procedure TForm1.btnIntfaceToGUIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
GUID:TGUID;
begin
GUID:=FirstIntfClass.GetIntfGUID(FirstIntf);
if GUID.D1>0 then
ShowMessage(GUIDToString(GUID));
end;

end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐