Esto lo solucioné yo mismo, implementado como un ayudante de clase para TObject, por lo que se puede usar en todas partes si la gente lo quiere. D2010 y más debido a RTTI, pero es posible que puedas convertirlo para usar material RTTI original.
El siguiente código puede tener errores ya que originalmente el mío era para DUnit y tenía muchos controles en lugar de cambiar el resultado y no es compatible con TCollections o una carga de otros casos especiales, pero se puede adaptar utilizando -elseif-luego cambia en el medio.
Si tiene alguna sugerencia e información adicional, no dude en hacer un comentario para que yo pueda agregarla y otras personas puedan usarla.
Diviértete codificación
Barry
unit TObjectHelpers;
interface
uses classes, rtti;
type
TObjectHelpers = class Helper for TObject
function DeepEquals (const aObject : TObject) : boolean;
end;
implementation
uses sysutils, typinfo;
{ TObjectHelpers }
function TObjectHelpers.DeepEquals(const aObject: TObject): boolean;
var
c : TRttiContext;
t : TRttiType;
p : TRttiProperty;
begin
result := true;
if self = aObject then
exit; // Equal as same pointer
if (self = nil) and (aObject = nil) then
exit; // equal as both non instanced
if (self = nil) and (aObject <> nil) then
begin
result := false;
exit; // one nil other non nil fail
end;
if (self <> nil) and (aObject = nil) then
begin
result := false;
exit; // one nil other non nil fail
end;
if self.ClassType <> aObject.ClassType then
begin
result := false;
exit;
end;
c := TRttiContext.Create;
try
t := c.GetType(aObject.ClassType);
for p in t.GetProperties do
begin
if ((p.GetValue(self).IsObject)) then
begin
if not TObject(p.GetValue(self).AsObject).DeepEquals(TObject(p.GetValue(aObject).AsObject)) then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'DateTime') or AnsiSameText(p.PropertyType.Name, 'TDateTime') then
begin
if p.GetValue(self).AsExtended <> p.GetValue(aObject).AsExtended then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'Boolean') then
begin
if p.GetValue(self).AsBoolean <> p.GetValue(aObject).AsBoolean then
begin
result := false;
exit;
end;
end
else if AnsiSameText(p.PropertyType.Name, 'Currency') then
begin
if p.GetValue(self).AsExtended <> p.GetValue(aObject).AsExtended then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkInteger then
begin
if p.GetValue(self).AsInteger <> p.GetValue(aObject).AsInteger then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkInt64 then
begin
if p.GetValue(self).AsInt64 <> p.GetValue(aObject).AsInt64 then
begin
result := false;
exit;
end;
end
else if p.PropertyType.TypeKind = tkEnumeration then
begin
if p.GetValue(self).AsOrdinal <> p.GetValue(aObject).AsOrdinal then
begin
result := false;
exit;
end;
end
else
begin
if p.GetValue(self).AsVariant <> p.GetValue(aObject).AsVariant then
begin
result := false;
exit;
end;
end;
end;
finally
c.Free;
end;
end;
end.
serialización a un formato de texto (XML, JSON) y haciendo un TDiff (http://angusj.com/delphi/) sería fácil – mjn
¿Qué tal Formato DFM :-) Es como un precursor JSON ... de 1995. –