vcl架构中TPersistent类的学习

来源:互联网 发布:apache maven下载 编辑:程序博客网 时间:2024/05/08 13:10

TPersistent类来源TObject类,在Delphi中的定义如下:

{$M+}

  TPersistent = class(TObject)

  private

    procedure AssignError(Source: TPersistent);

  protected

    procedure AssignTo(Dest: TPersistent); virtual;

    procedure DefineProperties(Filer: TFiler); virtual;

    function  GetOwner: TPersistent; dynamic;

  public

    destructor Destroy; override;

    procedure Assign(Source: TPersistent); virtual;

    function  GetNamePath: string; dynamic;

  end;

{$M-}

Vcl的基类TObject本身不支持RTTI(运行时类型信息)TPersistent类通过{$M+}编译指令提供了RTTI的功能,打开了M开关后,Delphi在编译该对象时,会把对象的类型信息也编译进可执行文件,这样在运行时就可以动态的获得对象的属性,方法等信息,所有的VCL可视化组件都是从TPersistent派生出来的,因此可以将组件信息保存成DFM文件,可以在运行时加载。

TPersistent的声明中,有两个Public的方法(Destroy在此不讨论),其中GetNamePathDelphi的集成开发环境内部使用的,VCL不推荐直接对它的调用。而Assign方法则是为完成对象复制而存在的,就是用来把一个源对象的属性复制到目标对象中,并且被声明为虚方法,以允许每个派生类定义自己的复制对象的方法。Assign方法只是简单的调用源对象的AssignTo方法来复制属性,而TPersistentAssignTo虚方法只是简单的抛出一个异常。也就是说TPersistent方法并没有实现任何有意义的功能,那么对于派生自TPersistent类的对象要想提供克隆的功能都需要重载TPersistentAssign或者AssignTo方法来实现自定义的复制功能,在Vcl中很多的类都实现了定制的Assign方法,比如最常见的TStrings类就重载了Assign方法提供了字符串列表的复制功能,在程序开发中经常会有需要将一个列表框的选项全部移动到另外一个列表中表示选择了全部的内容,这个过程其实就是一个克隆的过程,使用Assign方法来实现就非常简单,代码、效果图示意如下:

procedure TForm1.Button1Click(Sender: TObject);

begin

  ListBox2.Items.Assign(ListBox1.Items);

end;

http://p.blog.csdn.net/images/p_blog_csdn_net/hhf383530895/EntryImages/20090905/assign.jpg

如果没有重写Assign方法,则TPersistentAssign方法会将复制动作交给源对象来 进行:

procedure TPersistent.Assign(Source: TPersistent);

begin

   if Source <> nil then

     Source.AssignTo(Self) // 调用源对象的AssignTo方法

   Else

     AssignError(nil);

end;

可以在TPersistent类的声明的protected节中找到AssignTo方法的声明,它也是一个虚方法。

如果将复制动作交给源对象来完成,那么必须保证源对象的类已经重写了AssignTo方法,否则将抛出一个“Assign Error”异常:

procedure TPersistent.AssignError(Source: TPersistent);

var

  SourceName: string;

begin

  if Source <> nil then

SourceName := Source.ClassName

else

    SourceName := 'nil';

  raise EConvertError.CreateResFmt(@SAssignError, [SourceName, ClassName]);

end;

AssignError是一个private方法,仅仅用于抛出赋值错误的异常。

TPersistent的声明中,GetOwner方法是被前面所述由Delphi内部使用的GetNamePath所调用。

       最后还剩下一个虚方法DefineProperties(),它则是为TPersistent的另一个使命而存在:对象持久。一个对象要持久存在,就必须将它流化(Streaming),保存到一个磁盘文件(.dfm文件)中。TPersistent也使得其派生类具有这种能力,但它作为抽象类只是定义接口而并没有给出实现。可以看到,DefineProperties是一个空的虚方法:

 

procedure TPersistent.DefineProperties(Filer: TFiler);

 

begin

 

end;

 

这留待其派生类来实现。对于对象持久的实现类,最典型的就是TComponent,每个组件都具有保存自己的能力。持久化的核心类:TFilerTReaderTWriter,并使用继承的方式来实现。TFiler抽象类,定义持久化基本的服务接口,同是TReaderTWriter的抽象父类。

 

原创粉丝点击