前幾天做試著做了一個很簡單的控制項(是按 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