关于 TSpsistent中 Assign方法及 AssignTo方法的说明

前几天做试着做了一个很简单的控件(是按 d5 开发人员指南来做的)
这个控件用到了一个从 TPersistent 继承下来的类

type
    TSomeObject = class(TPersistent)
    private
      FProp1:integer;
      FProp2:string;
    public
      procedure Assign(source:TPersistent);override;
    published
      property  Prop1:integer read FProp1 write FProp1;
      property  Prop2:string read FProp2 write FProp2;
    end;

.
.
.
.

procedure TSomeObject.Assign(source:TPersistent);
begin
  if source is TSomeObject then
  begin
     self.FProp1:=TSomeObject(source).FProp1;
     self.FProp2:=TSomeObject(source).FProp2;
       
  end;
  inherited assign(source);
end;

按 d5中的例子打的,发现一用到 Assign 时总会提示 TSomeObject can not Assing To TSomeObject  这是

怎么回事呢?为什么会出现这个错误,看了看 TPersistent 别的派生类也是这样实现的呀,都 inherited

Assign(source); 我的怎么会错呢?后来试着加了一个 exit;

procedure TSomeObject.Assign(source:TPersistent);
begin
  if source is TSomeObject then
  begin
     self.FProp1:=TSomeObject(source).FProp1;
     self.FProp2:=TSomeObject(source).FProp2;
     exit;  
  end;
  inherited assign(source);
end;

错误没了,为什么 inherited assign(source) 会出错呢?于是查看源码终于找到答案


由于 TPersistent 中的 assign 是一个virtual 方法,没有具体的实现

<-----  TPersistent 中的源码  ------>

              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;

<----------------------------------->

从源码中可以看到

Assign  ->  AssignTo -> AssignError

不管 是 assign 还是 assignTo 最终要执行  AssignError 方法,所以这就要求继承自 TPersistent 的类要覆

盖 TPersistent 的 Assign 方法

<-----  TCollection  ----->

procedure TCollection.Assign(Source: TPersistent);
var
  I: Integer;
begin
  if Source is TCollection then
  begin
    BeginUpdate;
    try
      Clear;
      for I := 0 to TCollection(Source).Count - 1 do
        Add.Assign(TCollection(Source).Items[I]);
    finally
      EndUpdate;
    end;
    Exit;
    //  这里用到了 exit
  end;
  inherited Assign(Source);
end;

<------------------------->
 
同样 TStrings  类也是

<-----  TStrings  ----->

procedure TStrings.Assign(Source: TPersistent);
begin
  if Source is TStrings then
  begin
    BeginUpdate;
    try
      Clear;
      FDefined := TStrings(Source).FDefined;
      FQuoteChar := TStrings(Source).FQuoteChar;
      FDelimiter := TStrings(Source).FDelimiter;
      AddStrings(TStrings(Source));
    finally
      EndUpdate;
    end;
    Exit;
    // 同样这里也是 exit
  end;
  inherited Assign(Source);
end;

<---------------------->

通过以上可以看出 TPersistent 的派生类在覆盖 Assign 时,满足条件的的处理过程完成后要退出处理过程

,不要去 inherited Assign(source) , 因为这样最终会执行到 AssignError

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值