Глубокое Сравнение Объектов Delphi
ищет способ в Delphi сделать глубокое сравнение объектов для меня, предпочтительно 2010 RTTI, основанный на том, что мои объекты не наследуются от TComponent
. Я разрабатываю тестовую структуру в DUnit
и нужно что-то твердое, которое укажет, какое именно поле вызывает проблемы (сравнение сериализации оставляет его немного расплывчатым).
2 ответов
вроде решил это сам, реализован как помощник класса для TObject, поэтому может использоваться везде, если люди этого хотят. D2010 и выше из-за RTTI, но вы можете преобразовать его в оригинальный RTTI материал.
код ниже может быть багги, как первоначально мой был для DUnit и имел много проверок в нем вместо изменения результата и не поддерживает TCollections или нагрузку других особых случаев, но может быть адаптирован для этого с помощью переключателя if-elseif-then в средний.
Если у вас есть какие-либо предложения и дополнения, пожалуйста, не стесняйтесь комментировать, чтобы я мог добавить их к нему, чтобы другие люди могли использовать это.
получайте удовольствие кодирования
Барри
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.
рассмотрите возможность использования сохраняемость OmniXML.
для XML-дифференцирования я написал утилиту с использованием OmniXML, которая будет делать XML diff, и есть много инструментов сравнения XML.
Я использовал OmniXML для создания инструмента XML-дифференцирования именно для этой цели, и он отлично работал для меня. К сожалению, этот инструмент содержит много доменных вещей и является закрытым исходным кодом и принадлежит бывшему работодателю, поэтому я не могу опубликовать код.
мой инструмент сравнения имел простой алгоритм:
- сопоставление и построение карты связей узлов Object1->Object2 между соответствующими узлами XML.
- сортировка каждого узла на первичном ключе (знание конкретного домена) делает порядок XML неважным. Поскольку вы не только сравниваете компоненты с именами, вам нужно будет найти способ установить идентичность каждого объекта, если вы хотите его сравнить.
- элементы отчета в xml doc 1, которые не находятся в xml doc 2.
- элементы отчета в xml doc 2, которые не находятся в xml doc 1.
- элементы отчета в xml doc 1 с подразделами или атрибутами, отличными от xml doc2.
- visual tool использовал два виртуальных элемента управления древовидного представления и работал как KDIFF3, но как treeview.