Delphi.NET 内部实现分析(3.3)
2.3. 对象
接下来我们看看类的实例,对象的实现
//-----------------------------------------Borland.Delphi.System.pas--
type
TObject = System.Object;
TObjectHelper = class helper for TObject
procedure Free;
function ClassType: TClass;
class function ClassName: string;
class function ClassNameIs(const Name: string): Boolean;
class function ClassParent: TClass;
class function ClassInfo: TObject;
class function InheritsFrom(AClass: TClass): Boolean;
class function MethodAddress(const Name: string): TObject;
class function SystemType: System.Type;
function FieldAddress(const Name: string): TObject;
procedure Dispatch(var Message);
end;
//-----------------------------------------Borland.Delphi.System.pas--
从Borland.Delphi.System的定义中我们可以看到,TObject实际上就是System.Object的
别名而已,而真正的代码是通过class helper给TObject也就是System.Object打的补丁。
下面我们来仔细看看TObjectHelper的实现代码,理解Delphi是如何移植到CLR上的。
//-----------------------------------------Borland.Delphi.System.pas--
procedure TObjectHelper.Free;
begin
if (Self <> nil) and (Self is IDisposable) then
(Self as IDisposable).Dispose;
end;
//-----------------------------------------Borland.Delphi.System.pas--
与传统Delphi的用户自行管理内存模式不同,Delphi.NET使用CLR提供的自动内存管理机制,
有GC垃圾回收机制自动回收无用的内存。
但为了给用户一个自行控制外部资源(如文件句柄,网络连接)等稀缺资源的机会,CLR同时提供了
IDisposable接口这种妥协机制。一个类如果实现了IDisposable接口,则说明其有需要自己管理
生命周期的资源,可以通过IDisposable.Dispose方法手工释放。接口定义如下
IDisposable = interface
procedure Dispose;
end;
因而Delphi.NET的Free方法只是简单检测当前对象是否支持IDisposable接口,如支持则
直接调用IDisposable.Dispose释放资源。不过目前预览版对此接口的支持好像不是很好用 :(
如果以后能够支持象C#中using语句那样的功能就好了,呵呵
在TObjectHelper的实现中可以看到,对类方法如class function方法来说,
Self就是指向类的元类,因而ClassParent和ClassInfo方法直接从其元类获取信息。
//-----------------------------------------Borland.Delphi.System.pas--
class function TObjectHelper.ClassParent: TClass;
begin
Result := _TClass(Self).ClassParent;
end;
class function TObjectHelper.ClassInfo: TObject;
begin
Result := _TClass(Self).FInstanceType;
end;
//-----------------------------------------Borland.Delphi.System.pas--
而对于普通的方法,则需要将其转换为Token或Type再进行处理。ClassType和FieldAddress
就是两个很好的例子。前者使用刚刚提到的_GetMetaFromHandle函数从当前对象的类型Token
获取元类;后者则从当前对象的类型Type(CLR中类似元类的概念)获取指定名称字段的对象
//-----------------------------------------Borland.Delphi.System.pas--
function TObjectHelper.ClassType: TClass;
begin
Result := _GetMetaFromHandle(System.Type.GetTypeHandle(Self));
end;
function TObjectHelper.FieldAddress(const Name: string): TObject;
begin
Result := TypeOf(Self).GetField(Name);
end;
//-----------------------------------------Borland.Delphi.System.pas--
剩余方法的实现原理大同小异,无非是在对象、类、元类、Token和Type之间互相转换,获取所需的信息。
//-----------------------------------------Borland.Delphi.System.pas--
class function TObjectHelper.SystemType: System.Type;
begin
Result := System.Type.GetTypeFromHandle(_TClass(Self).FInstanceType);
end;
class function TObjectHelper.ClassName: string;
begin
Result := System.Type.GetTypeFromHandle(_TClass(Self).FInstanceType).Name;
end;
class function TObjectHelper.ClassNameIs(const Name: string): Boolean;
begin
Result := ClassName = Name;
end;
class function TObjectHelper.InheritsFrom(AClass: TClass): Boolean;
begin
Result := TypeOf(Self).IsInstanceOfType(TypeOf(AClass));
end;
class function TObjectHelper.MethodAddress(const Name: string): TObject;
begin
Result := TypeOf(Self).GetMethod(Name);
end;
//-----------------------------------------Borland.Delphi.System.pas--
余下一个TObjectHelper.Dispatch方法,后面分析Delphi.NET消息模型时再详谈。