2011-11-03 100 views
11

寻找一个delphi库或代码片段,将为我做深度对象比较,最好是基于RTTI的,因为我的对象不会从TComponent继承。有谁知道我在哪里可以找到一个,我正在开发一个测试框架在DUnit,并需要一些固体,它会指出究竟哪个字段导致问题(序列化比较离开它有点模糊)。深度对象比较Delphi

干杯,

巴里

+5

序列化到一个文本格式(XML,JSON),并做了TDIFF(http://angusj.com/delphi/)会很容易 – mjn

+1

怎么样DFM格式:-)它就像一个JSON前身...从1995年开始。 –

回答

12

解决这个问题的种类,作为TObject的类助手实现,所以如果人们需要它可以随处使用。 D2010和以上,因为RTTI,但你可能能够将其转换为使用原始RTTI的东西。

下面的代码可能是错误的,因为我原来是用于DUnit的,它有很多检查,而不是改变结果,不支持TCollections或其他特殊情况的负载,但可以通过使用if -elseif - 然后在中间切换。

如果您有任何建议和补充,请不要犹豫,以便我可以添加它,以便其他人可以使用它。

玩得开心编码

巴里

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. 
+3

非显着差异与显着差异如何? (例子:你是否曾经想过忽略窗口句柄值等差异的情况?你可以添加一个排除属性,以便深入比较可以跳过一些东西吗? –

+1

当有人对你的类型进行类型重定义时, –

+0

或者如果人们已经在使用他们自己的(或别人的)类助手来处理TObject,那么可以使用NOWHERE。对于大声喊叫,人们什么时候会停止使用类助手来处理那些单元级别的函数/程序足够好,而且更合理!!它确实看起来好像人们非常渴望为班级助手找到一个合法的用途,他们会在每个问题上抛出它们 - 其中99%是他们 – Deltics

4

考虑使用OmniXML persistence

对于XML差异,我已经使用OmniXML编写了一个实用程序,它将执行XML差异,并且有许多XML比较工具。

为了达到这个目的,我使用了OmniXML来完成XML差异化工具,它对我来说非常好。不幸的是,该工具包含许多特定领域的东西,并且是封闭源代码,属于前雇主,因此我无法发布代码。

我比较工具有一个简单的算法:

  1. 匹配和建立地图匹配的XML节点之间Object1->对象2节点的链接。
  2. 对主键上的每个节点进行排序(领域特定知识),使得XML顺序不重要。由于您不仅将TComponents与名称进行比较,您需要找到一种方法来建立每个对象的身份,如果您希望能够比较它。在XML文档1
  3. 报告项中没有的XML文档在XML文档2 2.
  4. 报告项中没有的XML文档在XML文档11.
  5. 报告项与子项或属性比XML不同DOC2。
  6. 可视化工具使用了两个虚拟树视图控件,并且像KDIFF3一样工作,但是作为树视图。
+0

这是一个很好的解决方案,但仍然有点太多开销和复杂,尤其是在用于DUnit测试时。我认为我刚刚写了一些能够完成这项工作的内容,我将其发布在 – Barry

+1

这正是我如何使用它; DUNIT。它在磁盘上创建了很多单元测试输出文件,这正是我需要查找,理解和修复正在发生的回归的东西。数据就是力量。 –

+0

啊不够公平,真的不同。测试套件必须由少数人使用,所以宁可让编码人员明白,他们必须先完成文件并进行检查。 – Barry