2011-11-03 91 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