亚历克斯我有同样的问题,因为你,我打破了他的头一点,写了下面的代码谁回答我问题,充满希望我也会见你或他人。
function TModel.Clone(pObj:TObject): TObject;
procedure WriteInField(pField:TRttiField; result, source:Pointer);
var
Field:TRttiField;
Val:TValue;
Len, I :Integer;
tp:TRttiType;
ctx:TRttiContext;
begin
if not pField.GetValue(source).IsEmpty then
case pField.FieldType.TypeKind of
TTypeKind.tkRecord:
begin
for Field in pField.FieldType.GetFields do
WriteInField(Field, PByte(result)+pField.Offset, pField.GetValue(source).GetReferenceToRawData);
end;
TTypeKind.tkClass:
begin
Val:=Self.Clone(pField.GetValue(source).AsObject);
if Assigned(TObject(pField.GetValue(result).AsObject)) then
pField.GetValue(result).AsObject.Free;
pField.SetValue(result,Val);
end;
TTypeKind.tkDynArray:
begin
Len := pField.GetValue(source).GetArrayLength;
for I := 0 to Len -1 do
case pField.GetValue(source).GetArrayElement(I).Kind of
TTypeKind.tkRecord:
begin
tp:=ctx.GetType(pField.GetValue(source).GetArrayElement(I).TypeInfo);
for Field in tp.GetFields do
WriteInField(Field,PByte(result)+Field.Offset, pField.GetValue(source).GetReferenceToRawData);
end;
TTypeKind.tkClass:
begin
Val:=Self.Clone(pField.GetValue(source).GetArrayElement(I).AsObject);
DynArraySetLength(PPointer(PByte(result)+pField.Offset)^,pField.GetValue(source).TypeInfo,1,@Len);
pField.GetValue(result).SetArrayElement(I,Val);
end;
else
DynArraySetLength(PPointer(PByte(result)+pField.Offset)^,pField.GetValue(source).TypeInfo,1,@Len);
pField.GetValue(result).SetArrayElement(I, pField.GetValue(source).GetArrayElement(I));
end;
end;
else
pField.SetValue(result,pField.GetValue(source));
end;
end;
var
Context: TRttiContext;
IsComponent, LookOutForNameProp: Boolean;
RttiType: TRttiType;
Method: TRttiMethod;
MinVisibility: TMemberVisibility;
Params: TArray<TRttiParameter>;
PropFild: TRttiField;
Fild: TRttiField;
SourceAsPointer, ResultAsPointer: Pointer;
ObjWithData:TObject;
Value:TValue;
begin
try
if Assigned(pObj) then
ObjWithData := pObj
else
ObjWithData := Self;
RttiType := Context.GetType(ObjWithData.ClassType);
//find a suitable constructor, though treat components specially
IsComponent := (ObjWithData is TComponent);
for Method in RttiType.GetMethods do
if Method.IsConstructor then
begin
Params := Method.GetParameters;
if Params = nil then Break;
if (Length(Params) = 1) and IsComponent and
(Params[0].ParamType is TRttiInstanceType) and
SameText(Method.Name, 'Create') then Break;
end;
if Params = nil then
Result := Method.Invoke(ObjWithData.ClassType, []).AsObject
else
Raise Exception.CreateFmt('Object Invalid to clone : ''%s''', [ObjWithData.ClassName]);
try
//loop through the props, copying values across for ones that are read/write
Move(ObjWithData, SourceAsPointer, SizeOf(Pointer));
Move(Result, ResultAsPointer, SizeOf(Pointer));
for PropFild in RttiType.GetFields do
WriteInField(PropFild,ResultAsPointer,SourceAsPointer);
except
Result.Free;
raise;
end;
finally
ObjWithData := nil;
end;
end;
杰里,这个类已经继承了TPersistent,并且Assign被覆盖。我必须手动分配数百个对象,除非有自动的方式。 (我试过调用继承的Assign,并且抛出了一个类似“无法将MyObject分配给MyObject”的错误,即使我在调用Assign之前检查了正确的对象类型,也是如此。) – Alex 2013-04-30 20:28:44
数百个成员?听起来你需要把这个坏男孩瘦下来。对于什么是值得的,这里有数百个持续性问题。已经有很多答案了。 – 2013-04-30 21:23:47
不,“分配”不能以这种方式工作。 **您**应该覆盖'AssignTo'并提供复制的意思 – OnTheFly 2013-04-30 22:09:31