CnPack 开源软件项目 - 关于 Assign 与 AssignTo 的 FAQ
  网站首页 下载中心 每日构建 文档中心 公益基金 开发论坛 关于我们 致谢名单 English


 Google 搜索

内容: 
 最新下载包


 
CnWizards 1.2.8.1150
[2023-11-01]

 
CnVCL 组件包 20231101
[2023-10-31]

 
CVSTracNT 多语言版 V2.0.1_20080601
[2008-06-02]

 
CVSTrac Linux 中文版 V1.2.1_20060112
[2006-01-12]
  最新开发版下载 RSS
  项目时间线 RSS RSS
 项目相关链接

CnPack GitHub 首页
GIT 使用说明
申请加入 CnPack
CnPack 成员名单
CnPack 邮件系统
 网站访问量

今日首页访问: 903
今日页面流量: 3374
全部首页访问: 5013802
全部页面流量: 19922274
建站日期: 2003-09-01

关于 Assign 与 AssignTo 的 FAQ

CnPack 开源软件项目 2007-04-25 23:58:53

CnPackTip#6 关于 Assign 与 Assignto 的 FAQ

http://www.cnpack.org
CnPack IV  QQ Group: 130970
感谢: JingYu, 小冬, 小峰, 小辉, 没人认识我, Bahamut  ...
整理: SkyJacker
转载请注明出处且保持完整
2007.04.25

FAQ: Assign 与 Assignto

Q:
TPersistent 的 Assign 与 Assignto 有什么区别?

如下 vcl 源码:
procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;
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;
procedure TPersistent.AssignTo(Dest: TPersistent);
begin
  Dest.AssignError(Self);
end;

A:
Assign是给子类重载使用的。
子类都可以重载以实现子类不同实例间的互相赋值。
单纯的TPersistent实例是不支持Assign的,一Assign就会按代码中所说那样弹出AssignError。
但子类是可以重载的。TStringList等,都重载实现了这些方法。

Q: AssignError 为什么每次都要 raise ?

A: TPersistent本类确实会 raise,子类一般override了,就没了。

Q: Assign 与 Assignto 为什么要这样设计呢?

A:
AssignTo 是非常有作用的,设计 Assign 和 Assignto 两个函数,是很有必要的。
Assign 是控制从其它对象给自身赋值
Assignto 是控制自身给其它对象赋值
这两个函数的区别就是主动与被动的关系

举个例子

Bitmap.Assign(JpegImage);
如果只提供 Assign 的话,Bitmap 不可能再去判断 Source 是否一个 JpegImage
而如果有 AssignTo 的话,Jpeg 就可以在这里给 Bitmap 传递数据
这样当 Bitmap.Assign(Jepg) 时,Bitmap 发现 Source 是个不支持的 Jpeg 对象,
就会调用 Jpeg.AssignTo(Self)。
这样就可以实现 对象.Assign(将来扩展的对象) 这个功能,
同样,如果我们要增加一个 TCnBitmap 这个扩展类,只要实现 AssignTo(Tbitmap),
就可以让 Bitmap.Assign(CnBitmap) 的功能了。
代码本身很简单,关键是要理解代码背后的思想。

Q: 能否解释一下源码

A:
procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;
这个缺省实现的意思是,如果将一个未知的对象赋值给自己,就调用未知对象的“给对方赋值”函数

Q:为什么 bitmap和jpeg可以Assign

A:
在 Assign 里面可以做数据格式转换,
Assign 就是提供给对象之间赋值数据的机制。
在 TPersistent 里,AssignTo 是 protected 方法,用户不需要调用的
对用户来说,Assign 是用来在相同或不同类型的对象之间传递数据的
对组件开发者来说,Assign 可以用来支持这种传递
TPersistent 是 vcl 体系的基石。意思是,可持久化的对象
这种持久化是通过将对象流化和反流化来实现的

  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+} 这个开关是用来为类生成 rtti 信息

想系统地理解,还是找本书来看吧
介绍 vcl 体系的书挺多的
对 Assign 和 Assignto 来说,两个函数都有用
如果你想让你写类能够 Assign 其它对象,需要 override Assign,
如果想让其它对象 Assign 你自己,需要 override AssignTo
所以一般子类重载的 Assign 实现体通常是:

if Source is TXXX then
begin
end
else if Source is XXX then
begin end
else
  inherited;

Q: 如果是两个不同对象呢? 比如 TBitMap 和 TString 如果想实现类似 lst.Assign(BitMap)呢?

A:
只要有这个需求,你也可以写个 TMyBitmap 来支持 Assign(TString) 和 AssignTo(TString)
都是判断 Source 的类型
lst.Assign(BitMap),只能是 lst.Assign(YourBitmap),
除非你 hook 掉 bitmap.AssignTo 或类似的地方。



本文已阅读 10910 次
来自: CnPack 开源软件项目

上一主题 | 返回上级下一主题

相关主题:


版权所有(C) 2001-2018 CnPack 开发组 网站编写:Zhou Jinyu