你为什么要用AS?一般说来,就是几个同一类型的控件对应一个共同的事件才用。如:Button1.OnClick:=ButtonClick;
Button1.Tag:=1;
Button2.OnClick:=ButtonClick;
Button2.Tag:=2;
Button3.OnClick:=ButtonClick;
Button3.Tag:=3;procedure TFormMain.ButtonClick(Sender: TObject);
begin
ShowMessage('Button'+IntToStr((Sender as TButton).Tag));
end;
Button1.Tag:=1;
Button2.OnClick:=ButtonClick;
Button2.Tag:=2;
Button3.OnClick:=ButtonClick;
Button3.Tag:=3;procedure TFormMain.ButtonClick(Sender: TObject);
begin
ShowMessage('Button'+IntToStr((Sender as TButton).Tag));
end;
这才像个技术问题!
这样来回答吧: 获取接口指针有三种方法,一种是直接分配,一种是as操作符,最后一种——后面讲。(一)第一种,如(对上面有修改)MyClass: TMyClass;
MyIntf: IMyInterface;MyClass:= TMyClass.Create(10); //必须有对象的实例
MyIntf := MyClass as IMyInterface;但是,有时不知道对象是否支持某接口,容易产生错误,所以一般使用对象的GetInterface函数(该函数是TObject的成员函数),如:MyClass:= TMyClass.Create(10);
if MyClass.GetInterface(IMyInterface,MyIntf) then
begin
//已经关联,MyIntf可以用了
//该干什么干什么
end;
(二)使用as操作符(注:使用getInterface和as操作符的共同前提是——必须同时赋予一个GUID),如:MyClass:= TMyClass.Create(10);
MyIntf := MyObj as IMyInterface;使用as操作符,若对象不支持接口,会产生一个异常。而TObject.GetInterface不会。
另一方面,GetInterface是TObject的成员函数,只能在对象上使用,而as还可以在接口本身中使用,如:procedure DoSomething(I:IUnkonw);
var
MyIntf:IMyInterface;
begin
(I as IMyInterface).Function; //Function指接口定义的某个函数
end;
而使用as会有一个副作用(也是上面出现问题的关键):使用as操作符,Delphi会调用_AddRef接口使用完成之后会调用_Release函数。
而在使用完as操作符之后,若此时对象的引用计数为0,则该对象将被立刻销毁,如:
begin
MyClass:= TMyClass.Create(10); DoSomething(MyClass as IMyInterface);//此句执行完成后,对象已经被销毁 MyClass.Function; //此处再调用其方法将出现错误
end;但如果上面的DoSomething是变参引用或常量引用,则上面引用代码将不会出错,譬如如下面声明:procedure DoSomething(var I:IUnkonw);
或
procedure DoSomething(const I:IUnkonw);因为他们是引用地址传递而不是值传递(引用地址传递,Delphi将不会调用_AddRef、_Release方法)。(三)绕过自动计数(不推荐使用,因为他不属于规范的代码设计)就是将上面的对象强制增加引用计数:begin
MyClass:= TMyClass.Create(10); MyClass._AddRef; //强制增加调用 DoSomething(MyClass as IMyInterface);//此句执行完成后,对象已经被销毁 MyClass.Function; //此处再调用其方法将出现错误 MyClass.Release; //恢复计数end;这样就不用去管DoSomething是如何声明的了!
>>---------------------------------------------------------------(附注说明)以上内容看完后,相信你仍然会觉得很不可理解!你可能会认为:(问题一)MyClass:= TMyClass.Create(10); //我已经将初始化的引用计数设置为10,怎么还会出现对象被销毁的情况???这便是Delphi的精妙之处!他在你的程序中间添加了一层东西——智能指针!使程序员从烦琐、恐怖的构造代码中解放出来。
Delphi中的智能指针是隐含编译的,这也是为什么你的接口引用代码为什么不用象C++中那样显式的调用_AddRef和_Release方法。不知道你是否对C++的智能指针有所了解?其实他相当于在接口和实现接口的对象实例中间添加了一层“安全引用计数”,是完全自动的。所以不管你设置对象实例的初始值是多少,都不会起作用! C++中,Interface被简单定义为等同于Struct的宏,而在我看来,Delphi中的Interface绝不会是那样一个简单的宏定义,因为他至少在编译时包含了智能指针!
(问题二)为什么将接口以值的形式传递给调用函数时可能会引发对象销毁?而使用var及const 不会?这就是接口规范!(设计规范,就是不要试图去改变的东西)接口规范包含数个部分,这里列出接口引用计数的规则:1、输入参数规则:对于传入函数的接口指针,无须调用AddRef和_Release。2、输出参数规则:任何输出参数中(或返回值)返回一个新的接口指针的函数都必须对此接口指针调用_AddRef,这条规则最经典的例子就是QueryInterface了!3、输入输出参数:对于输入输出参数传递进来的接口指针,必须在给它赋另外一个接口指针之前调用其_Release方法。在函数返回之前,还必须对输出参数中保存的接口指针调用AddRef。(我感觉C++的参数与Delphi中有一些微妙变化,自己去Discover吧!)
清晨愉快!